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 ++ v4.0/src/MEMM/MAKEFILE | 14 + v4.0/src/MEMM/MEMM/A20TRAP.ASM | 528 +++++++ v4.0/src/MEMM/MEMM/ALLOCMEM.ASM | 567 ++++++++ v4.0/src/MEMM/MEMM/ASCII_SM.EQU | 41 + v4.0/src/MEMM/MEMM/DESC.INC | 277 ++++ v4.0/src/MEMM/MEMM/DISP.INC | 50 + v4.0/src/MEMM/MEMM/DMA.INC | 234 +++ v4.0/src/MEMM/MEMM/DRIVER.EQU | 105 ++ v4.0/src/MEMM/MEMM/DRIVER.STR | 129 ++ v4.0/src/MEMM/MEMM/EKBD.ASM | 139 ++ v4.0/src/MEMM/MEMM/ELIM.INC | 128 ++ v4.0/src/MEMM/MEMM/ELIMFUNC.ASM | 268 ++++ v4.0/src/MEMM/MEMM/ELIMTRAP.ASM | 1560 ++++++++++++++++++++ v4.0/src/MEMM/MEMM/EM286LL.ASM | 360 +++++ v4.0/src/MEMM/MEMM/EM386LL.ASM | 397 ++++++ v4.0/src/MEMM/MEMM/EMM.ASM | 522 +++++++ v4.0/src/MEMM/MEMM/EMM386.INC | 49 + v4.0/src/MEMM/MEMM/EMM386.LNK | 41 + v4.0/src/MEMM/MEMM/EMM386D.LNK | 41 + v4.0/src/MEMM/MEMM/EMMCOM.LNK | 5 + v4.0/src/MEMM/MEMM/EMMINIT.ASM | 678 +++++++++ v4.0/src/MEMM/MEMM/EMMMES.ASM | 210 +++ v4.0/src/MEMM/MEMM/ERRHNDLR.ASM | 385 +++++ v4.0/src/MEMM/MEMM/EXTPOOL.ASM | 187 +++ v4.0/src/MEMM/MEMM/I286.ASM | 312 ++++ v4.0/src/MEMM/MEMM/I386.ASM | 240 ++++ v4.0/src/MEMM/MEMM/INIT.ASM | 1123 +++++++++++++++ v4.0/src/MEMM/MEMM/INITDEB.ASM | 180 +++ v4.0/src/MEMM/MEMM/INITEPG.ASM | 377 +++++ v4.0/src/MEMM/MEMM/INITTAB.ASM | 632 +++++++++ v4.0/src/MEMM/MEMM/INSTR386.INC | 563 ++++++++ v4.0/src/MEMM/MEMM/IOTRAP.ASM | 165 +++ v4.0/src/MEMM/MEMM/KBD.ASM | 1608 +++++++++++++++++++++ v4.0/src/MEMM/MEMM/KBD.INC | 99 ++ v4.0/src/MEMM/MEMM/LOADALL.INC | 173 +++ v4.0/src/MEMM/MEMM/MACH_ID.INC | 38 + v4.0/src/MEMM/MEMM/MAKEFILE | 343 +++++ v4.0/src/MEMM/MEMM/MAPDMA.ASM | 633 +++++++++ v4.0/src/MEMM/MEMM/MAPDMA.C | 425 ++++++ v4.0/src/MEMM/MEMM/MAPLIN.ASM | 172 +++ v4.0/src/MEMM/MEMM/MEMM386.ASM | 561 ++++++++ v4.0/src/MEMM/MEMM/MEMMCOM.ASM | 243 ++++ v4.0/src/MEMM/MEMM/MEMMINC.ASM | 80 ++ v4.0/src/MEMM/MEMM/MEMMONF.ASM | 337 +++++ v4.0/src/MEMM/MEMM/MEMM_MSG.INC | 43 + v4.0/src/MEMM/MEMM/MOVEB.ASM | 533 +++++++ v4.0/src/MEMM/MEMM/M_STATE.ASM | 114 ++ v4.0/src/MEMM/MEMM/OEMDEP.INC | 111 ++ v4.0/src/MEMM/MEMM/OEMPROC.ASM | 1120 +++++++++++++++ v4.0/src/MEMM/MEMM/PAGE.INC | 52 + v4.0/src/MEMM/MEMM/PIC_DEF.EQU | 78 + v4.0/src/MEMM/MEMM/PPAGE.ASM | 510 +++++++ v4.0/src/MEMM/MEMM/PRINT.ASM | 424 ++++++ v4.0/src/MEMM/MEMM/RETREAL.ASM | 228 +++ v4.0/src/MEMM/MEMM/ROMSTRUC.EQU | 37 + v4.0/src/MEMM/MEMM/ROMXBIOS.EQU | 45 + v4.0/src/MEMM/MEMM/ROM_SRCH.ASM | 317 +++++ v4.0/src/MEMM/MEMM/RRTRAP.ASM | 436 ++++++ v4.0/src/MEMM/MEMM/SHIPHI.ASM | 325 +++++ v4.0/src/MEMM/MEMM/TABDEF.ASM | 357 +++++ v4.0/src/MEMM/MEMM/TRAPDEF.ASM | 469 ++++++ v4.0/src/MEMM/MEMM/UTIL.ASM | 335 +++++ v4.0/src/MEMM/MEMM/VDMINIT.ASM | 527 +++++++ v4.0/src/MEMM/MEMM/VDMSEG.INC | 168 +++ v4.0/src/MEMM/MEMM/VDMSEL.INC | 101 ++ v4.0/src/MEMM/MEMM/VM386.INC | 206 +++ v4.0/src/MEMM/MEMM/VMINIT.ASM | 292 ++++ v4.0/src/MEMM/MEMM/VMINST.ASM | 2135 ++++++++++++++++++++++++++++ v4.0/src/MEMM/MEMM/VMTRAP.ASM | 791 +++++++++++ 79 files changed, 31239 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 create mode 100644 v4.0/src/MEMM/MAKEFILE create mode 100644 v4.0/src/MEMM/MEMM/A20TRAP.ASM create mode 100644 v4.0/src/MEMM/MEMM/ALLOCMEM.ASM create mode 100644 v4.0/src/MEMM/MEMM/ASCII_SM.EQU create mode 100644 v4.0/src/MEMM/MEMM/DESC.INC create mode 100644 v4.0/src/MEMM/MEMM/DISP.INC create mode 100644 v4.0/src/MEMM/MEMM/DMA.INC create mode 100644 v4.0/src/MEMM/MEMM/DRIVER.EQU create mode 100644 v4.0/src/MEMM/MEMM/DRIVER.STR create mode 100644 v4.0/src/MEMM/MEMM/EKBD.ASM create mode 100644 v4.0/src/MEMM/MEMM/ELIM.INC create mode 100644 v4.0/src/MEMM/MEMM/ELIMFUNC.ASM create mode 100644 v4.0/src/MEMM/MEMM/ELIMTRAP.ASM create mode 100644 v4.0/src/MEMM/MEMM/EM286LL.ASM create mode 100644 v4.0/src/MEMM/MEMM/EM386LL.ASM create mode 100644 v4.0/src/MEMM/MEMM/EMM.ASM create mode 100644 v4.0/src/MEMM/MEMM/EMM386.INC create mode 100644 v4.0/src/MEMM/MEMM/EMM386.LNK create mode 100644 v4.0/src/MEMM/MEMM/EMM386D.LNK create mode 100644 v4.0/src/MEMM/MEMM/EMMCOM.LNK create mode 100644 v4.0/src/MEMM/MEMM/EMMINIT.ASM create mode 100644 v4.0/src/MEMM/MEMM/EMMMES.ASM create mode 100644 v4.0/src/MEMM/MEMM/ERRHNDLR.ASM create mode 100644 v4.0/src/MEMM/MEMM/EXTPOOL.ASM create mode 100644 v4.0/src/MEMM/MEMM/I286.ASM create mode 100644 v4.0/src/MEMM/MEMM/I386.ASM create mode 100644 v4.0/src/MEMM/MEMM/INIT.ASM create mode 100644 v4.0/src/MEMM/MEMM/INITDEB.ASM create mode 100644 v4.0/src/MEMM/MEMM/INITEPG.ASM create mode 100644 v4.0/src/MEMM/MEMM/INITTAB.ASM create mode 100644 v4.0/src/MEMM/MEMM/INSTR386.INC create mode 100644 v4.0/src/MEMM/MEMM/IOTRAP.ASM create mode 100644 v4.0/src/MEMM/MEMM/KBD.ASM create mode 100644 v4.0/src/MEMM/MEMM/KBD.INC create mode 100644 v4.0/src/MEMM/MEMM/LOADALL.INC create mode 100644 v4.0/src/MEMM/MEMM/MACH_ID.INC create mode 100644 v4.0/src/MEMM/MEMM/MAKEFILE create mode 100644 v4.0/src/MEMM/MEMM/MAPDMA.ASM create mode 100644 v4.0/src/MEMM/MEMM/MAPDMA.C create mode 100644 v4.0/src/MEMM/MEMM/MAPLIN.ASM create mode 100644 v4.0/src/MEMM/MEMM/MEMM386.ASM create mode 100644 v4.0/src/MEMM/MEMM/MEMMCOM.ASM create mode 100644 v4.0/src/MEMM/MEMM/MEMMINC.ASM create mode 100644 v4.0/src/MEMM/MEMM/MEMMONF.ASM create mode 100644 v4.0/src/MEMM/MEMM/MEMM_MSG.INC create mode 100644 v4.0/src/MEMM/MEMM/MOVEB.ASM create mode 100644 v4.0/src/MEMM/MEMM/M_STATE.ASM create mode 100644 v4.0/src/MEMM/MEMM/OEMDEP.INC create mode 100644 v4.0/src/MEMM/MEMM/OEMPROC.ASM create mode 100644 v4.0/src/MEMM/MEMM/PAGE.INC create mode 100644 v4.0/src/MEMM/MEMM/PIC_DEF.EQU create mode 100644 v4.0/src/MEMM/MEMM/PPAGE.ASM create mode 100644 v4.0/src/MEMM/MEMM/PRINT.ASM create mode 100644 v4.0/src/MEMM/MEMM/RETREAL.ASM create mode 100644 v4.0/src/MEMM/MEMM/ROMSTRUC.EQU create mode 100644 v4.0/src/MEMM/MEMM/ROMXBIOS.EQU create mode 100644 v4.0/src/MEMM/MEMM/ROM_SRCH.ASM create mode 100644 v4.0/src/MEMM/MEMM/RRTRAP.ASM create mode 100644 v4.0/src/MEMM/MEMM/SHIPHI.ASM create mode 100644 v4.0/src/MEMM/MEMM/TABDEF.ASM create mode 100644 v4.0/src/MEMM/MEMM/TRAPDEF.ASM create mode 100644 v4.0/src/MEMM/MEMM/UTIL.ASM create mode 100644 v4.0/src/MEMM/MEMM/VDMINIT.ASM create mode 100644 v4.0/src/MEMM/MEMM/VDMSEG.INC create mode 100644 v4.0/src/MEMM/MEMM/VDMSEL.INC create mode 100644 v4.0/src/MEMM/MEMM/VM386.INC create mode 100644 v4.0/src/MEMM/MEMM/VMINIT.ASM create mode 100644 v4.0/src/MEMM/MEMM/VMINST.ASM create mode 100644 v4.0/src/MEMM/MEMM/VMTRAP.ASM (limited to 'v4.0/src/MEMM') 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; + diff --git a/v4.0/src/MEMM/MAKEFILE b/v4.0/src/MEMM/MAKEFILE new file mode 100644 index 0000000..e9c4c70 --- /dev/null +++ b/v4.0/src/MEMM/MAKEFILE @@ -0,0 +1,14 @@ +#************************* Root level Makefile ************************* + +make =nmake + +all: + cd emm + $(make) + cd ..\memm + $(make) + cd .. + + + + diff --git a/v4.0/src/MEMM/MEMM/A20TRAP.ASM b/v4.0/src/MEMM/MEMM/A20TRAP.ASM new file mode 100644 index 0000000..2f7f377 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/A20TRAP.ASM @@ -0,0 +1,528 @@ + + +page 58,132 +;****************************************************************************** + title A20TRAP.ASM - I/O trap handlers for watching the A20 line. +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: A20TRAP.ASM - I/O trap handlers for watching the A20 line. +; +; Version: 0.03 +; +; Date: June 1, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 07/03/86 0.03 From ChkDisA20 routine in VMINST. +; +;****************************************************************************** +; +; Functional Description: +; This module contains the I/O trap handlers for the A20 line watching +; logic. +; +; +; COMMENTS: This module displays weaknesses due to carryover from previous +; sources. A lot of the code here can be shifted to the LAST +; segment. There is a duplication of routines for getting the a20 +; state. (ISP) +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public A20_Handler + public A20_Trap_Init + public EnableA20 + public DisableA20 + public togl_A20 + public get_a20_state + public estb_a20_state + public get_init_a20_state + + +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** + include VDMseg.inc + include VDMsel.inc +; +_DATA segment +; (none) +_DATA ends + +_TEXT segment + + extrn PortTrap:near + +_TEXT ends + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +FALSE equ 0 +TRUE equ not FALSE + +YesLLdone equ 1 +KbdDataEnb equ 2 + +A20CmdBit equ 02h ; high is enabled +A20DsbCmd equ 0DDh +A20EnbCmd equ 0DFh + +KbdCmdPort equ 64h ; 8042 cmd port +KbdWrtData equ 0D1h ; Enable write to data port +KbdDataPort equ 60h ; 8042 data port +KbdStatusPort equ 64h ; 8042 cmd port +KbdBufFull equ 2 ; Buffer bull(data not received) status + +; equates for the state_a20 flag + +A20_ON equ A20CmdBit ; +A20_OFF equ 0 ; +; +; equate for the bit which will toggle the state of +; +WRAP_BIT equ 00100000h ; page table entry bit +; +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; + +; +; _DATA segment +; +_DATA segment + +KbdComd db 0 ; last CMD written to port 64h +state_a20 db 0 ; A20 line state: A20_ON is on, A20_OFF is off + +_DATA ends + +; + page +;------------------------------------------------------------------------------ +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP +; +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** +; + +;****************************************************************************** +; A20_Handler - I/O trap handler for Address line 20 modification +; +; ENTRY: Protected Mode Ring 0 +; AL = byte to output to port. +; BX == 2 * port address(either KbdDataPort or KbdCmdPort) +; DX == 0 => Emulate input +; <> 0 => Emulate output +; DS = DGROUP +; SS:BP = points to stack frame on entry to GP fault handler +; +; EXIT: +; CLC => I/O emulated. +; STC => I/O NOT emulated. +; +; USED: BX,Flags +; STACK: +;------------------------------------------------------------------------------ +A20_Handler proc near + or dx,dx ;Q: Output ? + jnz A20_Write ; Y: check for write to output port + stc ; N: don't bother to emulate it + ret +A20_Write: + cmp bx,KbdDataPort*2 ;Q: Keyboard data port? + jne Kbd_C_Handler ; N: Go handle Kybd Command output + ; Y: Go handle Kybd Data output + +; keyboard data write +Kbd_D_Dwrite: + cmp [KbdComd],KbdWrtData ;Q: write to output port? + mov [KbdComd],0 ; data port write => no CMD + je Kbd_D_out ; Y: filter client's data + stc ; N: don't bother to emulate it + ret +; +; here if Output Port write +; +Kbd_D_out: + push ax ; Set A20 cmd bit + call check_a20_togl ; do we need to toggle the + ; the a20 state + jz skip_togl ; N: Skip routine to toggle + call togl_a20 +skip_togl: + or al, A20CmdBit ; to leave A20 enabled + out KbdDataPort,al ; "emulate" it + pop ax ; restore client's byte + clc ; emulated + ret + +;Output to Keyboard command port +Kbd_C_Handler: +; + mov [KbdComd],al ; Y: save new port 64 byte + stc ; don't bother to emulate it + ret +; +A20_Handler endp + + +;****************************************************************************** +; A20_Trap_Init - turn on I/O bit map trapping for A20 line watching +; +; ENTRY: DS -> DGROUP - real,virtual, or protected mode +; ES -> TSS segment +; IOTrap_Tab already has address of A20_Handler for KbdDataPort and +; KbdCmdPort +; +; EXIT: IO_BitMap Updated to trap ports used to change A20 line +; +; USED: AX,Flags +; STACK: +;------------------------------------------------------------------------------ +A20_Trap_Init proc near +; +; reset flag +; + mov [KbdComd],0 +; +; Set IOBM traps to look for client's disabling of the A20 line +; + mov bh, 80h ; set every 1k + mov ax, KbdDataPort + call PortTrap ; set traps on keyboard ports + mov ax, KbdCmdPort ; in case client + call PortTrap ; tries to disable A20 + ret +; +A20_Trap_Init endp +; +;*****************************************************************************; +;*** EnableA20 - switch 20th address line ; +; ; +; This routine is used to enable the 20th address line in ; +; the system. ; +; ; +; In general when in real mode we want the A20 line disabled, ; +; when in protected mode enabled. However if there is no high ; +; memory installed we can optimise out unnecessary switching ; +; of the A20 line. Unfortunately the PC/AT ROM does not allow ; +; us to completely decouple mode switching the 286 from gating ; +; the A20 line. ; +; ; +; In real mode we would want A20 enabled if we need to access ; +; high memory, for example in a device driver. We want it ; +; disabled while running arbitrary applications because they ; +; may rely on the 1 meg address wrap feature which having the ; +; A20 line off provides. ; +; ; +; This code is largely duplicated from the PC/AT ROM BIOS. ; +; See Module "BIOS1" on page 5-155 of the PC/AT tech ref. ; +; ; +; ENTRY none ;ds = DGROUP ; +; EXIT A20 line enabled ; +; USES ax, flags modified ; +; ; +; WARNING: ; +; ; +; The performance characteristics of these routines ; +; are not well understood. There may be worst case ; +; scenarios where the routine could take a relatively ; +; long time to complete. ; +; ; +; TO BE ADDED: ; +; ; +; 8042 error handling ; +;*****************************************************************************; +EnableA20 proc near + mov ah,0dfh ; code for enable + jmp a20common ; jump to common code + +EnableA20 endp + +;*****************************************************************************; +;*** DisableA20 - switch 20th address line ; +; ; +; This routine is used to disable the 20th address line in ; +; the system. ; +; ; +; ENTRY none ;ds = DATA ; +; EXIT A20 line disabled ; +; [state_a20] = 0 ; +; USES ax, flags modified ; +;*****************************************************************************; + +DisableA20 proc near + mov ah,0ddh ; code for disable + jmp a20common ; jump to common code + +DisableA20 endp + + +a20common proc near + +; This is entered via a jmp from one of the two procedural +; entry points above. + + call empty_8042 ; ensure 8042 input buffer empty + jnz com1 ; 8042 error return + mov al,0d1h ; 8042 cmd to write output port + out KbdCmdPort,al ; send cmd to 8042 + call empty_8042 ; wait for 8042 to accept cmd + jnz com1 ; 8042 error return + mov al,ah ; 8042 port data + out KbdDataPort,al ; output port data to 8042 + call empty_8042 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; AST P/386 needs the delay for their +; A20 switch settle. If not, it won't work ! +; PC (10/03/88) +; + push cx + mov cx, 0100h +ASTloop: + loop ASTloop + pop cx +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +com1: + ret +a20common endp + +;*****************************************************************************; +;*** empty_8042 - wait for 8042 input buffer to drain ; +; ; +; ENTRY none ; +; EXIT al=0, z=0 => 8042 input buffer empty ; +; al=2, z=1 => timeout, input buffer full ; +; USES none ; +;*****************************************************************************; +empty_8042 proc near + push cx ; save it + sub cx,cx ; cx = 0, timeout loop counter +emp1: + in al,KbdStatusPort ; read 8042 status port + and al,KbdBufFull ; test buffer full bit + loopnz emp1 + pop cx + ret +empty_8042 endp + +;*****************************************************************************; +;*** check_a20_togl - check if a20 state emulated needs to be toggled ; +; ; +; ENTRY [state_a20] = A20 emulated state ; +; al = byte to output to kbd data port ; +; EXIT Z set if A20 not to be toggled ; +; clear if A20 to be toggled ; +; USES Flags ; +; ; +;*****************************************************************************; +check_a20_togl proc near +; + push ax + and al,A20CmdBit ; make all other bits 0 + xor al,[state_a20] ; does the state of the a20 bit match + ; Y: then Z is set + ; N: then Z is not set + pop ax + ret +; +check_a20_togl endp + + +;*****************************************************************************; +;*** get_a20_state - see if virtualised a20 is enabled or not ; +; ; +; ENTRY [state_a20] = A20 emulated state ; +; ; +; EXIT ZF set if A20 disabled ; +; ZF not set if A20 enabled ; +; ; +; USES Flags ; +;*****************************************************************************; + +get_a20_state proc near +; + test [state_a20], A20_ON + ret +get_a20_state endp + + +;*****************************************************************************; +;*** togl_A20 - toggle emulated A20 state. ; +; ; +; ENTRY [state_a20] = A20 emulated state ; +; PROTECTED MODE ONLY ; +; DS:DGROUP ; +; ; +; EXIT [state_a20] toggled ; +; page table entries for the 1M --> 1M + 64k area toggled ; +; ; +; USES Flags ; +; ; +; ; +;*****************************************************************************; +togl_A20 proc near +; + push es + push di + push cx + push eax +; +; get addressability to page table +; + push PAGET_GSEL + pop es +; +; and offset into entries for the 64k block at 1M +; + mov di,100h*4 ; 1024k/4k = 256 entries, each 4 bytes long + mov cx,10h ; 64k/4k = 16 entries + cld +; +; for all the entries flip the bit which will make the entries either wrap +; around for 1M-1M+64k to either 1M-1M+64k or 0-64k. This bit is the 1M bit +; in the base address. +; +w64_loop: + xor dword ptr es:[di], WRAP_BIT + add di,4 + loop w64_loop +; +; flush the tlb +; + mov eax,cr3 + mov cr3,eax +; +; toggle a20 state +; + xor [state_a20],A20_ON +; +; restore the registers +; + pop eax + pop cx + pop di + pop es + ret +; +togl_A20 endp + + + +_TEXT ends ; end of segment + +LAST segment + + assume cs:LAST, ds:DGROUP, es:DGROUP, ss:DGROUP + + +;****************************************************************************** +;***estb_a20_state ; +; ; +; since we are fixing the a20 state to be always enabled we need to implement ; +; a logical a20 state independent of the physical one. this routine inits ; +; this state. we do this comparing 3 double words at 0:80 and 1M:80. if these; +; compare the a20 is disabled thus causing a wraparound. ; +; ; +; INPUTS: ; +; ; +; OUTPUTS: [state_a20] .. A20_ON if a20 is on currently ; +; .. A20_OFF if a20 is off currently ; +; ; +; USES: flags ; +; ; +; AUTHOR: ISP. Shifted in from smartdrv sources. 8/29/88. ; +; ; +;*****************************************************************************; +; A20 address line state determination addresses +; + low_mem label dword + dw 20h*4 + dw 0 + + high_mem label dword + dw 20h*4 + 10h + dw 0ffffh + +estb_a20_state proc near + push cx + push ds + push es + push si + push di + ; + ; initialise a20 to off + ; + mov [state_a20],A20_OFF + ; + ; compare 3 dwords at 0:80h and 1M:80h. if these are equal then + ; we can assume that a20 is off + ; + lds si,cs:low_mem + ASSUME DS:NOTHING + les di,cs:high_mem + ASSUME ES:NOTHING + mov cx,3 + cld +repe cmpsd + pop di + pop si + pop es + pop ds + ASSUME DS:DGROUP,ES:DGROUP + jcxz not_enabled + ; + ; a20 is on + ; + mov [state_a20],A20_ON +not_enabled: + pop cx + ret +estb_a20_state endp + +;*****************************************************************************; +;*** get_init_a20_state - see if virtualised a20 is enabled or not ; +; ; +; ENTRY [state_a20] = A20 state at startup ; +; ; +; EXIT ZF set if A20 disabled ; +; ZF not set if A20 enabled ; +; ; +; USES Flags ; +;*****************************************************************************; + + ASSUME DS:DGROUP,ES:NOTHING + +get_init_a20_state proc near +; + test [state_a20], A20_ON + ret +get_init_a20_state endp + +LAST ends + + end ; end of module + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/ALLOCMEM.ASM b/v4.0/src/MEMM/MEMM/ALLOCMEM.ASM new file mode 100644 index 0000000..430f849 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ALLOCMEM.ASM @@ -0,0 +1,567 @@ + + + page 58,132 +;****************************************************************************** + title ALLOCMEM - allocate memory for EMM Pages Pool +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: AllocMem - allocate memory for EMM Pages Pool +; +; Version: 0.05 +; +; Date: May 24,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 05/24/86 Original +; 06/28/86 0.02 code read changes to various routines +; 07/05/86 0.04 Changes due to segment re-org +; 07/06/86 0.04 Made EXT_RES a define +; 07/06/86 0.04 Changed to DGROUP assume +; 07/10/86 0.05 added NOHIMEM flag +; 06/02/88 pc change from VDISK allocation to INT-15 method +; 07/26/88 isp completed work in changing over to int15 alloc +; +;****************************************************************************** +; Functional Description: +; This module allocates the pool of memory to be used for the pool of +; EMM pages. The pool of memory is allocated from "high" extended +; memory (located in the 15-16 Meg range)and from "regular" extended memory +; (starting at 1 Meg). This module attempts to allocate high memory first, +; then extended memory. When allocating memory from either area, the memory +; is allocated in 16k byte blocks which are aligned on a physical 4k boundary. +; This module attempts to allocate extended memory using the int15 allocation +; scheme. +; +; NOTE: if this module is compiled with NOHIMEM defined, then +; this code will not attempt to use the OEM specific +; "high" memory. +; +;****************************************************************************** +.lfcond +.386p +; +; +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public AllocMem + public DeallocMem + public xbase_addr_l ; data publics + public xbase_addr_h + public ext_size + public sys_size + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include vdmseg.inc + include vdmsel.inc + include emm386.inc + include driver.equ + include driver.str + include romxbios.equ + include desc.inc + include ascii_sm.equ + include oemdep.inc + include emmdef.inc +; +EXT_RES equ 10h ; must be a power of 2. +; +GET_VER equ 30h ; get dos version number +MSDOS equ 21h ; DOS interrupt +; +FALSE equ 0 +TRUE equ not FALSE + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +_DATA segment + + extrn dos_version:byte + extrn pool_size:word + extrn msg_flag:word + +ifndef NOHIMEM + extrn hi_size:word ; size of hi memory in kbytes + extrn hi_alloc:word ; hi memory allocated + extrn hisys_alloc:word ; hi system memory allocated + ; in 4k byte blocks +endif + +_DATA ends + + +LAST segment + extrn mappable_segs:byte ; mappable segment map + extrn set_ext:near ; routine to set amount of ext mem + ; reported by int15 handler + extrn memreq:near ; memory requirements for move + extrn pool_initialise:near ; initialise the pool of extended + ; memory + +ifndef NOHIMEM + extrn hbuf_chk:near + extrn HiAlloc:near + extrn HiMod:near +endif +LAST ends +; + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + + page +;****************************************************************************** +; Data segment +;****************************************************************************** +_DATA segment + ASSUME CS:DGROUP,DS:DGROUP + +xbase_addr_l dw 0000h ; 24 bit address of beginning of +xbase_addr_h db 10h ; extended mem pool of EMM pages. (1M initially) +ext_size dw 0 ; size of extended memory allocated in kb +sys_size dw 0 ; size of system memory from 4000h in emm pool +total_mem dw 0 ; size of extended memory available at any moment +avail_mem dw 0 ; total size (hi+ext) available for MEMM +; + +_DATA ends + + +;****************************************************************************** +; +; Code Segment +; +;****************************************************************************** +; +LAST segment + assume cs:LAST, ds:DGROUP, es:DGROUP + + page +;****************************************************************************** +; +; AllocMem Allocate Extended memory for MEMM using the int15 +; method of allocating extended memory. +; +; description: +; This routine attempts to get the requested extended memory +; from two sources: a) the himem area (just below 16M) first +; and if not enough b) extended memory. Extended memory is +; allocated using the int15 scheme. We do not care for +; compatibility with vdisk. The memory we allocate either in +; himem area or in extended memory must start at a 4k boundary +; because we are using them as pages. +; +; entry: DS pts to DGROUP +; DGROUP:[pool_size] = mem size requested (kbytes) +; +; exit: If extended memory pool space is not available then +; set MEM_ERR_MSG bit in DGROUP:[msg_flag] and exit. +; +; +; used: none +; +; stack: +; +; modified: ISP 07/26/88 Changed to a simple check for availability +; of hi / ext memory and allocation of +; of appropriate amounts of each. +; +; +;****************************************************************************** +; +AllocMem proc near +; + push ax + push bx + push cx + push dx + push es + + +; +; 1. Check available hi/extended memory +; +AM_getmem: + call xbuf_chk + test [msg_flag],MEM_ERR_MSG ;Q: memory error found ? + jz AM_nba ; N: continue with allocation + jmp AM_exit ; Y: exit +; +; 2. Allocate extended memory +; +AM_nba: + call ExtAlloc ; alloc ext mem + +ifndef NOHIMEM ; if HI memory in this model +; +; 3. Allocate Hi memory +; +AM_halloc: + call HiAlloc ; Allocate hi memory + jnc AM_exit ; no error + or [msg_flag],MEM_ERR_MSG ; memory error +endif + +; +; 4. Allocate system memory +; + call SysAlloc +; +AM_exit: + pop es + pop dx + pop cx + pop bx + pop ax + ret +AllocMem endp ; End of procedure +; + page +;****************************************************************************** +; +; DeallocMem Deallocate Extended memory for MEMM using the int15 +; method of allocating extended memory. Note that since +; we call this routine when we haven't already installed tc.) +; the int15 handler we really don't need to do anything +; as far as the regular extended memory is concerned. We +; only need to deallocate hi memory if allocated. +; +; entry: DS pts to DGROUP +; DGROUP:[hi_alloc] amount of hi memory to deallocate +; +; used: none +; +; stack: +; +; modif: 7/26/88 ISP Removed VDISK deallocation of extended memory +;****************************************************************************** +; +DeallocMem proc near + push ax + push bx + push cx + push dx + push si + push es +; +ifndef NOHIMEM ; if high memory in this model + mov ax,[hi_alloc] ; get hi memory to deallocate + or ax,ax ; q: did we ever get any? + jz deall_hisys ; n: check hi system memory + neg ax ; # of 16 byte pieces to remove + mov [hi_alloc],0 ; make sure we never do it again +deall_hisys: + mov bx,[hisys_alloc] ; get hi system memory to deallocate + neg bx ; update by a negative amount + add bx,ax ; q: any hi or hisys to deallocate? + jz deall_ext ; n: don't waste our time doing it + sub bx,ax ; y: straighten our regs out + mov [hisys_alloc],0 ; make sure we don't do it again + call HImod ; modify memory. ignore any errors +deall_ext: +; +endif ; end of conditional + pop es + pop si + pop dx + pop cx + pop bx + pop ax +; + ret +DeallocMem endp +; + page +;****************************************************************************** +; +; xbuf_chk Extended memory pool check. +; Check 1) for previously loaded MEMM,VDISKs in extended memory +; 2) available memory pool space. (hi memory and extended) +; +; entry: DS = DGROUP +; DGROUP:[pool_size] = mem size requested (kbytes) +; +; +; exit: If hi memory pool space is available then +; +; DGROUP:[hi_size] = hi memory size allocated (kbytes). +; +; If extended memory pool space is necessary and available then +; +; DGROUP:[xbase_addr_h] and DGROUP:[xbase_addr_l] contain the +; starting 24-bit address of MEMM extended memory pool. +; +; DGROUP:[pool_size] = mem size ALLOCATED (kbytes) +; DGROUP:[total_mem] = total extended memory left after allocation +; DGROUP:[avail_mem] = available memory for MEMM. +; DGROUP:[ext_size] = extended memory size allocated (kbytes) +; +; If hi/extended memory pool space is not available then +; set MEM_ERR_MSG bit in DGROUP:[msg_flag] and exit. +; +; used: none +; +; stack: +; +; modified: ISP 07/26/88 int15 allocation requires different check +; on extended memory. substancial rewrite. +;****************************************************************************** +; +xbuf_chk proc near +; + push ax + push bx + push cx + push dx + push di +; +; determine amount of extended memory and store it in total_mem +; + mov ah,EXT_MEM ; function request - ext mem data + clc ; clear carry flag + int XBIOS ;Q: extended memory supported ? +; + jnc store_ext ; Y: go to store the amount got + xor ax,ax ; N: Assume zero extended memory +store_ext: + mov [total_mem],ax +; +ifndef NOHIMEM ; if high memory in this model +; +; check for hi memory +; + call hbuf_chk ; get available hi memory in AX + jc xb_NoHiMem + mov [hi_size],ax ; save it + mov [avail_mem],ax ; update available memory +xb_NoHiMem: + mov ax,[pool_size] + cmp ax,[hi_size] ; q: enough? + ja get_ext ; n: try extended memory + mov [hi_size],ax ; y: just use enough + jmp x_buf_exit ; and exit +endif + +get_ext: + mov ax,[total_mem] ; get size of extended memory available + ; Y: how much there ? +; +; we have to reserve enough memory here to ship the segments up hi. +; + call memreq ; get memory requirements for our o + ; our grand operation in cx in K + cmp ax,cx ; lets see if we can satisfy + jbe x_buf_no_install ; if not we shan't install memm + + push ax + sub ax,cx + cmp ax,64 + 64 ; we should try to leave enough memory + ; for himem and atleast four pages of + ; expanded memory. + pop ax + jbe x_buf_no_install ; if we don't have enough for this we + ; shouldn't install memm + ; + ; we can now get memory to shift things up. and intialise the manager of + ; this pool. + ; + sub ax,cx ; ax = start of this pool as an offset + ; in K from 1M + ; cx = size in K of this pool + call pool_initialise ; intialise the pool + or ax,ax ;Q: any extended memory ? + jz x_buf_2 ; N: If none go to set buf adj or no + ; memory error +; ; Y: continue to process +; + mov bx,[pool_size] ; get size requested +; +ifndef NOHIMEM ; if high memory in this model + sub bx,[hi_size] ; adjust by the size already allocated +endif ; from the high memory + + and ax,0fff0h ; round to 16k boundary +; +; it is necessary to support himem. So if we have a 64k block at 1M we +; should leave it for himem. The himem we are talking about here is the +; EMS 4.1 standard himem at 1M + ; + ; initialise reserved memory for himem + ; + xor cx,cx ; amount reserved for himem + ; + ; see if we have 64k available for himem + ; + cmp ax,64 ; Q:do we have 64k? + jb no_himem_alloc ; N: we reserve nothing for himem + ; Y: we should reserve 64k for himem + ; + ; reserve 64k for himem + ; + mov cx,64 + sub ax,cx + ; +no_himem_alloc: + ; + cmp ax,bx ; compare amount available to size needed + jae enough_mem ; Y: fine + mov bx,ax ; N: adjust size reuested to size avail +enough_mem: + ; + ; add back the memory reserved for himem as this figures in the size of + ; free extended memory + ; + add ax,cx ; adjust size to include amnt res. himem + sub ax,bx ; adjust the size of extended memory + ; after allocation + mov [total_mem],ax ; store size of extended mem available +; + add [avail_mem],bx ; add memory available to memory pool + mov [ext_size],bx ; and indicate size allocated +; +; find the start address of extended memory allocated +; + mov cx,1024 ; kb multiplier + mul cx ; dx:ax = ax*cx + add [xbase_addr_l],ax ; adjsut starting address of allocated mem + adc [xbase_addr_h],dl ; higher byte of 24 bit address +; +x_buf_2: +; + mov ax,[avail_mem] ; ax == Available memory + cmp ax,[pool_size] ; Q: Extended memory available? + jnb x_buf_exit ; Y: Go to finish +; +not_enough: + or ax,ax ; Q: Any extended memory available? + jz x_buf_no_install ; N: Set error flag and exit + mov [pool_size],ax ; Y: Set pool_size to remaining memory + or [msg_flag],SIZE_ADJ_MSG ; Set buffer adjusted message bit + jmp short x_buf_exit ; And jump to exit +; +x_buf_no_install: + or [msg_flag],MEM_ERR_MSG ; memory error found in x_bufchk +; +x_buf_exit: + pop di + pop dx + pop cx + pop bx + pop ax + ret ; *** return *** +; +xbuf_chk endp +; + page +;****************************************************************************** +; +; ExtAlloc - allocate extended memory - update break address for ext. mem. +; +; entry: DS pts to DGROUP +; +; exit: extended memory size +; +; used: none. int15 size reported by int 15 handler in MEMM adjusted. +; +; stack: +; +; modified: ISP 07/26/88 Substancially simplified. For int15 scheme +; allocation is by lowering the size of int15 +; reported extended memory size. +; +;****************************************************************************** +ExtAlloc proc near +; + mov bx,[total_mem] ;size left after allocation to MEMM + call set_ext ; set this size in the int15 handler + ret +; +ExtAlloc endp +; +;****************************************************************************** +; +; SysAlloc - allocate extended memory - update break address for ext. mem. +; +; entry: DS pts to DGROUP +; +; exit: system memory size +; +; used: none. +; +; stack: +; +; written: ISP 07/28/88 This allocates the system memory from 0000H +; to A000h to the EMM pool. This is for the LIM +; 4.0 implementation. +; +;****************************************************************************** + +SysAlloc proc near +; + push ax + push bx + push cx +; +; find end of memory reported by bios int 12 and round this to upper 16k. +; + int 12h + add ax,0000fh ; + and ax,0fff0h ; round it 16k figure +; +; convert this to the a page # +; + shr ax, 4 ; number of 16k pages +; +; start search for pages which can be reclaimed from the system mem. region +; + mov cx,ax ; number of pages from pg0 to be examined + mov [sys_size],0 ; initialise the system memory allocate + xor bx,bx ; page # + + jcxz find_sys_done +find_sys_page: + cmp cs:mappable_segs[bx], PAGE_MAPPABLE + jne find_next_sys + add [sys_size],16 ; page found add 16k to system mem size +find_next_sys: + inc bx + loop find_sys_page +find_sys_done: + + mov ax,[sys_size] ; find the total memory found + add [pool_size],ax ; add this to the pool size + +; + pop cx + pop bx + pop ax + ret + +SysAlloc endp + + + +LAST ends ; End of segment +; + end ; End of module + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/ASCII_SM.EQU b/v4.0/src/MEMM/MEMM/ASCII_SM.EQU new file mode 100644 index 0000000..c4f656b --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ASCII_SM.EQU @@ -0,0 +1,41 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: ASCII_SM.EQU - ASCII (1968) control characters (small version) +; +; Version: 0.02 +; +; Date: June 25,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/25/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif +NUL equ 0 ; 00 ^@ Null +BEL equ 7 ; 07 ^G Bell +BS equ 8 ; 08 ^H Backspace +TAB equ 9 ; 09 ^I (Horizontal) Tab +LF equ 10 ; 0A ^J Line Feed +FF equ 12 ; 0C ^L Form Feed +CR equ 13 ; 0D ^M Carriage Return +ASCII_ESC equ 27 ; 1B ^[ Escape +SPACE equ 32 ; 20 Space +DEL equ 127 ; 7F Delete/Rubout + +.list ; end of ASCII_SM.EQU diff --git a/v4.0/src/MEMM/MEMM/DESC.INC b/v4.0/src/MEMM/MEMM/DESC.INC new file mode 100644 index 0000000..229fccb --- /dev/null +++ b/v4.0/src/MEMM/MEMM/DESC.INC @@ -0,0 +1,277 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: DESC.INC - Descriptor Table Definitions for 286/386 +; +; Version: 0.02 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 04/07/86 A added bit map base to 386 TSS +; 05/12/86 B Cleanup and segment reorganization +; 06/25/86 0.02 removed A0 macros +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +; --------------------------------------------------- +; +; Definitions for the access byte in a descriptor +; +; --------------------------------------------------- + + +; Following fields are common to segment and control descriptors + +D_PRES equ 080h ; present in memory +D_NOTPRES equ 0 ; not present in memory + +D_DPL0 equ 0 ; Ring 0 +D_DPL1 equ 020h ; Ring 1 +D_DPL2 equ 040h ; Ring 2 +D_DPL3 equ 060h ; Ring 3 + +D_SEG equ 010h ; Segment descriptor +D_CTRL equ 0 ; Control descriptor + + +; Following fields are specific to control descriptors + +D_TSS equ 01h ; A Free TSS +D_LDT equ 02h ; LDT +D_TSS_BUSY equ 03h ; A Busy TSS +D_CALLGATE equ 04h ; call gate +D_TASKGATE equ 05h ; task gate +D_INTGATE equ 06h ; interrupt gate +D_TRAPGATE equ 07h ; trap gate + ; 8 is invalid +D_386TSS equ 9 ; available 386 TSS + ; 0ah - Intel Reserved +D_BUSY386TSS equ 0bh ; busy 386 TSS +D_386CALL_GATE equ 0ch ; 386 call gate + ; 0dh - Intel Reserved +D_386INT_GATE equ 0eh ; 386 interrupt gate +D_386TRAP_GATE equ 0fh ; 386 trap gate + +; Following fields are specific to segment descriptors + +D_CODE equ 08h ; code +D_DATA equ 0 ; data + +D_CONFORM equ 04h ; if code, conforming +D_EXPDN equ 04h ; if data, expand down + +D_RX equ 02h ; if code, readable +D_X equ 0 ; if code, exec only +D_W equ 02h ; if data, writable +D_R equ 0 ; if data, read only + +D_ACCESSED equ 1 ; segment accessed bit + + +; Useful combination access rights bytes + +D_DATA0 equ (D_PRES+D_DPL0+D_SEG+D_DATA+D_W) ; Ring 0 rw data +D_CODE0 equ (D_PRES+D_DPL0+D_SEG+D_CODE+D_RX) ; Ring 0 rx code +D_TRAP0 equ (D_PRES+D_DPL0+D_CTRL+D_TRAPGATE) ; Ring 0 trap gate +D_INT0 equ (D_PRES+D_DPL0+D_CTRL+D_INTGATE) ; Ring 0 int gate +D_TSS0 equ (D_PRES+D_DPL0+D_CTRL+D_TSS) ; Ring 0 TSS +D_386TSS0 equ (D_PRES+D_DPL0+D_CTRL+D_386TSS) ; Ring 0 TSS +D_LDT0 equ (D_PRES+D_DPL0+D_CTRL+D_LDT) ; Ring 0 LDT +D_386INT0 equ (D_PRES+D_DPL0+D_CTRL+D_386INT_GATE) ; Ring 0 int gate + +;D_DATA1 equ (D_PRES+D_DPL1+D_SEG+D_DATA+D_W) ; Ring 1 rw data +;D_CODE1 equ (D_PRES+D_DPL1+D_SEG+D_CODE+D_RX) ; Ring 1 rx code + +;D_DATA2 equ (D_PRES+D_DPL2+D_SEG+D_DATA+D_W) ; Ring 2 rw data +;D_CODE2 equ (D_PRES+D_DPL2+D_SEG+D_CODE+D_RX) ; Ring 2 rx code + +D_DATA3 equ (D_PRES+D_DPL3+D_SEG+D_DATA+D_W) ; Ring 3 rw data +D_CODE3 equ (D_PRES+D_DPL3+D_SEG+D_CODE+D_RX) ; Ring 3 rx code +D_INT3 equ (D_PRES+D_DPL3+D_CTRL+D_INTGATE) ; Ring 3 int gate +D_GATE3 equ (D_PRES+D_DPL3+D_CTRL+D_CALLGATE) ; Ring 3 call gate +D_386INT3 equ (D_PRES+D_DPL3+D_CTRL+D_386INT_GATE) ; Ring 3 int gate + +; 386 Extensions + +D_B_BIT equ (1 SHL 6) ; 32 bit stack offsets + + +; Masks for selector fields + +SELECTOR_MASK equ 0fff8h ; selector index +SEL_LOW_MASK equ 0f8h ; mask for low byte of sel indx +TABLE_MASK equ 04h ; table bit +RPL_MASK equ 03h ; privilige bits +RPL_CLR equ not 03h ; clear ring bits + + +; Machine Status Word bits + +MSW_PROTECT equ 1 ; virtual mode bit + + +; System IOPL + +SYS_IOPL equ 3000h ; wide open +CLEAR_IOPL equ 0cfffh ; mask to remove IOPL bits + + +; Kernel Stack Size (TO BE ADDED) + +STK_SIZE equ 4000h ; TO BE ADDED + + +; -------------------------------------------------- +; +; Macros for creating descriptor table entries +; +; -------------------------------------------------- + + + +; structure for 386 descriptor + +desc struc +LIMIT dw 0 ; offset of last byte in segment +BASE_LOW dw 0 ; Low 16 bits of 24 bit base address +BASE_HIGH db 0 ; High 8 bits of 24 bit base address +RIGHTS db 0 ; access rights +RES386 db 0 ; reserved for 386 +BASE_XHI db 0 ; High 8 bits of 32 bit base address +desc ends + +; MASK for RES386 + +R_GRAN equ 10000000b ; granularity bit +R_AVL equ 00010000b ; available +R_LIMIT_XHI equ 00001111b ; limit bits 16..19 + +; IDT_ENTRY - for interrupt and task gate definitions in IDT + +IDT_ENTRY macro sel, off, acc + dw off ; offset + dw sel ; selector + db 0 ; word count, unused for trap/int gates + db acc ; access rights byte + dw 0 ; reserved, must be 0 for 386 +endm + + +; GDT_ENTRY - for static initialisation of GDT entries + +GDT_ENTRY macro BaseLow, BaseHi, Size, Access + dw Size - 1 ; segment limit + dw BaseLow ; low word of 24 bit base address + db BaseHi ; high byte of base address + db Access ; access rights byte + dw 0 ; reserved, must be 0 for 386 +endm + + +; LDT_ENTRY - for static initialisation of LDT entries + +LDT_ENTRY macro BaseLow, BaseHi, Size, Access + dw Size - 1 ; segment limit + dw BaseLow ; low word of 24 bit base address + db BaseHi ; high byte of base address + db Access ; access rights byte + dw 0 ; reserved, must be 0 for 386 +endm + + +;*** 286 TSS Format +; + +TSS286STRUC struc + + TSS286_BackLink dw 0 ; back link selector to TSS + TSS286_SP0 dw 0 ; ring 0 sp + TSS286_SS0 dw 0 ; ring 0 ss + TSS286_SP1 dw 0 ; ring 1 sp + TSS286_SS1 dw 0 ; ring 1 ss + TSS286_SP2 dw 0 ; ring 2 sp + TSS286_SS2 dw 0 ; ring 2 ss + TSS286_IP dw 0 ; entry point IP + TSS286_Flags dw 0 ; flag word + TSS286_AX dw 0 ; AX + TSS286_CX dw 0 ; CX + TSS286_DX dw 0 ; DX + TSS286_BX dw 0 ; BX + TSS286_SP dw 0 ; SP + TSS286_BP dw 0 ; BP + TSS286_SI dw 0 ; SI + TSS286_DI dw 0 ; DI + TSS286_ES dw 0 ; ES + TSS286_CS dw 0 ; CS + TSS286_SS dw 0 ; SS + TSS286_DS dw 0 ; DS + TSS286_LDT dw 0 ; LDT + +TSS286STRUC ends + +;*** 386 TSS Format +; + +TSS386STRUC struc + + TSS386_BackLink dw 0 ; back link selector to TSS + TSS386_Unused1 dw 0 ; unused + TSS386_ESP0lo dw 0 ; ring 0 ESP low word + TSS386_ESP0hi dw 0 ; ring 0 ESP high word + TSS386_SS0 dw 0 ; ring 0 SS + TSS386_Unused2 dw 0 ; unused + TSS386_ESP1 dd 0 ; ring 1 ESP + TSS386_SS1 dw 0 ; ring 1 SS + TSS386_Unused3 dw 0 ; unused + TSS386_ESP2 dd 0 ; ring 2 ESP + TSS386_SS2 dw 0 ; ring 2 SS + TSS386_Unused4 dw 0 ; unused + TSS386_CR3 dd 0 ; CR3 + TSS386_EIP dd 0 ; EIP + TSS386_EFLAGS dd 0 ; EFLAGS + TSS386_EAX dd 0 ; EAX + TSS386_ECX dd 0 ; ECX + TSS386_EDX dd 0 ; EDX + TSS386_EBX dd 0 ; EBX + TSS386_ESP dd 0 ; ESP + TSS386_EBP dd 0 ; EBP + TSS386_ESI dd 0 ; ESI + TSS386_EDI dd 0 ; EDI + TSS386_ES dw 0 ; ES + TSS386_Unused5 dw 0 ; Unused + TSS386_CS dw 0 ; CS + TSS386_Unused6 dw 0 ; Unused + TSS386_SS dw 0 ; SS + TSS386_Unused7 dw 0 ; Unused + TSS386_DS dw 0 ; DS + TSS386_Unused8 dw 0 ; Unused + TSS386_FS dw 0 ; FS + TSS386_Unused9 dw 0 ; Unused + TSS386_GS dw 0 ; GS + TSS386_Unused10 dw 0 ; Unused + TSS386_LDT dw 0 ; LDT + TSS386_Unused11 dw 0 ; Unused + TaskAttributes dw 0 ; Task Attributes + BitMapBase dw 0 ; offset of Base of Bit Map +TSS386STRUC ends + +.list ; end of DESC.INC + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/DISP.INC b/v4.0/src/MEMM/MEMM/DISP.INC new file mode 100644 index 0000000..96eeb7b --- /dev/null +++ b/v4.0/src/MEMM/MEMM/DISP.INC @@ -0,0 +1,50 @@ +extrn PrintString:near +extrn PrintHex:near + +display macro string + local dbs,disp_exit + pushf + push ds + push es + + push cs + pop ds + push cs + pop es + + push si + mov si,offset cs:dbs + call PrintString + pop si + pop es + pop ds + popf + jmp disp_exit + +dbs db &string,0 + +disp_exit: + endm + +content macro reg + pushf + push ds + push es + push ax + + mov ax,reg + + push cs + pop ds + push cs + pop es + + call PrintHex + + pop ax + pop es + pop ds + popf + endm + + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/DMA.INC b/v4.0/src/MEMM/MEMM/DMA.INC new file mode 100644 index 0000000..06bed73 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/DMA.INC @@ -0,0 +1,234 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: ELIM.INC - include for LIM I/O traps (DMA ports) +; +; Version: 0.03 +; +; Date: April 9, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/09/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/01/86 0.03 DMA trapping related equates added +; +; DATE AUTHOR DESCRIPTION +; ------- -------- ------------------------------------------------------- +; 06/21/88 ISP Removed the Intel Above Board Port Definitions +; 07/27/88 JHB Added Channel 4 ports, ports for Mode Regs and changed +; DMARegRec and DMARegBuf structure definitions - lifted +; from vdmad.inc in Win386/2.03. +; - Jaywant H Bharadwaj +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif +; +; +; DMA related ports +; +DMA_P0 equ 0087h ; DMA page register for Channel 0 +DMA_P1 equ 0083h ; DMA page register for Channel 1 +DMA_P2 equ 0081h ; DMA page register for Channel 2 +DMA_P3 equ 0082h ; DMA page register for Channel 3 +DMA_P5 equ 008Bh ; DMA page register for Channel 5 +DMA_P6 equ 0089h ; DMA page register for Channel 6 +DMA_P7 equ 008Ah ; DMA page register for Channel 7 +DMA_P4 equ 0080h ; dummy page reg for channel 4 + +DMA_B0 equ 0000h ; DMA base register for Channel 0 +DMA_C0 equ 0001h ; DMA count register for Channel 0 +DMA_B1 equ 0002h ; DMA base register for Channel 1 +DMA_C1 equ 0003h ; DMA count register for Channel 1 +DMA_B2 equ 0004h ; DMA base register for Channel 2 +DMA_C2 equ 0005h ; DMA count register for Channel 2 +DMA_B3 equ 0006h ; DMA base register for Channel 3 +DMA_C3 equ 0007h ; DMA count register for Channel 3 +DMA_B4 equ 00C0h ; DMA base register for Channel 4 +DMA_C4 equ 00C2h ; DMA count register for Channel 4 +DMA_B5 equ 00C4h ; DMA base register for Channel 5 +DMA_C5 equ 00C6h ; DMA count register for Channel 5 +DMA_B6 equ 00C8h ; DMA base register for Channel 6 +DMA_C6 equ 00CAh ; DMA count register for Channel 6 +DMA_B7 equ 00CCh ; DMA base register for Channel 7 +DMA_C7 equ 00CEh ; DMA count register for Channel 7 + +DMA1_CLR_FF equ 000Ch ; clear flip-flop cmd for channels 0-3 +DMA2_CLR_FF equ 00D8h ; clear flip-flop cmd for channels 5-7 + + +DMA1_MODE equ 000Bh ; Mode register for channels 0-3 +DMA2_MODE equ 00D6h ; Mode register for channels 4-7 + +DMA_M_CHANNEL equ 03h ; Mask for channel +DMA_M_OPERATION equ 0Ch ; Mask for operation +DMA_M_16BIT equ 040h ; 16bit transfers (PS/2 ext mode) + +DMA_M_VERIFY equ 0 ; Verify operation +DMA_M_WRITE equ 4 ; Write + + +;************************************************************************** +; New defintions for DMARegRec and DMARegBuf - 7/27/88 +; +; +; DMA Register Save Structure +; + +; +; note: the DMA code in ELIMTRAP.ASM is tuned to this structure's size = 16 +; if you change the size, you had better change the code ! +; LinAdr and PhysAdr have to be dwords +; count though 16 bits long is left as a dword since the rest of the ported +; 386 code is dependent on this structure being 16 bytes long. +; + +DMARegRec struc +DMALinAdr dd 00000000 ; Channel Linear Base Register +DMAPhyAdr dd 00000000 ; Channel Physical Base Register +DMACount dd 00000000 ; Channel Count Register +DMAPagePort db ? ; byte addr of page reg +DMABasePort db ? ; byte addr of base addr reg +DMACntPort db ? ; byte addr of cnt addr reg +DMAMode db ? ; Mode register +DMARegRec ends + +DMARegBuf struc +Chnl0 db (size DMARegRec - 4) dup (00), DMA_P0, DMA_B0, DMA_C0, 0 +Chnl1 db (size DMARegRec - 4) dup (00), DMA_P1, DMA_B1, DMA_C1, 0 +Chnl2 db (size DMARegRec - 4) dup (00), DMA_P2, DMA_B2, DMA_C2, 0 +Chnl3 db (size DMARegRec - 4) dup (00), DMA_P3, DMA_B3, DMA_C3, 0 +Chnl4 db (size DMARegRec - 4) dup (00), DMA_P4, DMA_B4, DMA_C4, DMA_M_16BIT +Chnl5 db (size DMARegRec - 4) dup (00), DMA_P5, DMA_B5, DMA_C5, DMA_M_16BIT +Chnl6 db (size DMARegRec - 4) dup (00), DMA_P6, DMA_B6, DMA_C6, DMA_M_16BIT +Chnl7 db (size DMARegRec - 4) dup (00), DMA_P7, DMA_B7, DMA_C7, DMA_M_16BIT +DMAFF1 db 00 ; Controller 1 FlipFlop State +DMAFF2 db 00 ; Controller 2 FlipFlop State +DMA_Xfun db 0 ; Extended Operation Function +DMA_Xchn db 0 ; Extended Operation Channel +DMARegBuf ends + +DMAREG_CTRL2_INDEX equ 4 * 2 ; 2 * 1st channel # on 2nd cntlr + + +;************************************************************************** +; +; Macros taken from PS2.INC in Win/386 2.03 +; +;-------------------------------------------------------------------------- + +; STANDARD ROM BIOS MACHINE TYPES used in ROM_BIOS_Machine_ID + +RBMI_PC equ 0FFh +RBMI_PCXT equ 0FEh +RBMI_PCjr equ 0FDh +RBMI_PCAT equ 0FCh +RBMI_PCConvertible equ 0F9h +RBMI_Sys80 equ 0F8h +RBMI_CompaqPortable equ 000h + +;****************************************************************************** +; DMA_WADDR_TO_BADDR - convert internal DMA word address to a byte address +; +; ENTRY: 386 PROTECTED MODE +; DS -> 0 +; ES -> 0 +; EAX - Word Address +; +; EXIT: EAX - Byte address +; +; USED: +;------------------------------------------------------------------------------ +DMA_WADDR_TO_BADDR MACRO + LOCAL Not_AT +extrn ROM_BIOS_Machine_ID:byte + + cmp [ROM_BIOS_Machine_ID], RBMI_Sys80 + jbe short Not_AT ; If running on EBIOS machine + + ror eax,16 ; AX = high word + shr al,1 ; adjust for D0 null in page reg + rol eax,17 ; EAX = address w/ adjust for + ; 'A0' offset +Not_At: + shl ecx, 1 ; Adjust for word units + ENDM + + +;****************************************************************************** +; DMA_BADDR_TO_WADDR - convert internal DMA byte address to a word address +; +; ENTRY: 386 PROTECTED MODE +; DS -> 0 +; ES -> 0 +; EAX - Word Address +; +; EXIT: EAX - Byte address +; +; USED: +;------------------------------------------------------------------------------ +DMA_BADDR_TO_WADDR MACRO + LOCAL Not_AT +extrn ROM_BIOS_Machine_ID:byte + + cmp [ROM_BIOS_Machine_ID], RBMI_Sys80 + jbe short Not_AT ; If running on EBIOS machine + + shr eax, 1 ; Adjust for implied 'A0' + push ax ; Save A16-A1 + xor ax, ax + shl eax, 1 ; Adjust for unused Pg Reg D0 + pop ax ; Restore A16-A1 +Not_At: + ENDM + + + +;**************************************************************************** +; Old definitions for memm LIM 3.2 - not used anymore - 7/27/88 +; +; DMA Register Save Structure +; +;Chnl1Idx equ 0 ; Address offset in Address tables +;Chnl2Idx equ 2 ; Address offset in Address tables +;Chnl3Idx equ 4 ; Address offset in Address tables +;Chnl5Idx equ 6 ; Address offset in Address tables +;Chnl6Idx equ 8 ; Address offset in Address tables +;Chnl7Idx equ 10 ; Address offset in Address tables +; +;DMARegRec struc +;DMALinAdr dd 00000000 ; Channel Linear Base Register +;DMAPhyAdr dd 00000000 ; Channel Physical Base Register +;DMACount dd 00000000 ; Channel Count Register +;DMAChnlIdx db ? ; Channel identifier index +;DMARegRec ends +; +;DMARegBuf struc +;Chnl1 db (size DMARegRec - 1) dup (00), Chnl1Idx +;Chnl2 db (size DMARegRec - 1) dup (00), Chnl2Idx +;Chnl3 db (size DMARegRec - 1) dup (00), Chnl3Idx +;Chnl5 db (size DMARegRec - 1) dup (00), Chnl5Idx +;Chnl6 db (size DMARegRec - 1) dup (00), Chnl6Idx +;Chnl7 db (size DMARegRec - 1) dup (00), Chnl7Idx +;DMAFF1 db 00 ; Controller 1 FlipFlop State +;DMAFF2 db 00 ; Controller 2 FlipFlop State +;DMARegBuf ends +; +;****************************************************************************** + + +.list ; end of ELIM.INC + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/DRIVER.EQU b/v4.0/src/MEMM/MEMM/DRIVER.EQU new file mode 100644 index 0000000..8e12e90 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/DRIVER.EQU @@ -0,0 +1,105 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: DRIVER.EQU - MS-DOS device driver equates +; +; Version: 0.02 +; +; Date: June 25, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/25/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif +; +; Device driver attribute equates +; +CHAR_DEV EQU 8000H +IOCTL_SUP EQU 4000H +NON_IBM EQU 2000H +CLK_DEV EQU 0008H +NUL_DEV EQU 0004H +OUT_DEV EQU 0002H +INP_DEV EQU 0001H +; +; Device driver command code equates +; +INIT EQU 0 +MEDIA EQU 1 +BUILD_BPB EQU 2 +IOCTL_INP EQU 3 +INPUT_READ EQU 4 +NON_INPUT EQU 5 +INP_STATUS EQU 6 +INP_FLUSH EQU 7 +OUTPUT_WRITE EQU 8 +OUTPUT_VER EQU 9 +OUT_STATUS EQU 10 +OUT_FLUSH EQU 11 +IOCTL_OUT EQU 12 +; +; Device driver status word equates +; +ERROR EQU 8000H +BUSY EQU 0200H +DONE EQU 0100H +ERR EQU 80H +BUS EQU 02H +DON EQU 01H +; +; Device driver i/o control status word equates +; +ISDEV EQU 0080H +EOF EQU 0040H +RAW EQU 0020H +ISCLK EQU 0008H +ISNUL EQU 0004H +ISCOT EQU 0002H +ISCIN EQU 0001H +; +; Device driver error code equates +; +WRT_PROT_VIO EQU 00H +UNK_UNIT EQU 01H +DEV_NOT_RDY EQU 02H +UNK_COMMAND EQU 03H +CRC_ERROR EQU 04H +BAD_DRIVE EQU 05H +SEEK_ERROR EQU 06H +UNK_MEDIA EQU 07H +SEC_NOT_FND EQU 08H +OUT_OF_PAPER EQU 09H +WRITE_FAULT EQU 0AH +READ_FAULT EQU 0BH +GENERAL_FAIL EQU 0CH +; +; Device driver function call equates +; +NUMBER_UNITS EQU BYTE PTR 0DH +ENDING_ADDR EQU DWORD PTR 0EH +BPB_ARRAY EQU DWORD PTR 12H +DESC_BYTE EQU BYTE PTR 0DH +RETURN_INFO EQU BYTE PTR 0EH +BUFFER_ADDR EQU DWORD PTR 0EH +BPB_PTR EQU DWORD PTR 12H +TRANS_COUNT EQU WORD PTR 12H +TRANS_ADDR EQU WORD PTR 14H +BYTE_READ EQU BYTE PTR 0DH + +.list ; end of DRIVER.EQU diff --git a/v4.0/src/MEMM/MEMM/DRIVER.STR b/v4.0/src/MEMM/MEMM/DRIVER.STR new file mode 100644 index 0000000..dfb7e90 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/DRIVER.STR @@ -0,0 +1,129 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: DRIVER.STR - MS-DOS Device Driver structures +; +; Version: 0.02 +; +; Date: June 25,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/25/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +; +; Device driver header structure +; +DEVICE_HEADER STRUC +DEV_PTR DD 0 +DEV_ATTR DW 0 +STRAT_PTR DW 0 +INT_PTR DW 0 +DEV_NAME DB " " +DEVICE_HEADER ENDS +DEV_OFF EQU WORD PTR DEV_PTR +DEV_SEG EQU WORD PTR DEV_PTR+2 +; +; Device driver request header structure +; +REQUEST_HEADER STRUC +HDR_LEN DB 0 +UNIT_CODE DB 0 +COMMAND_CODE DB 0 +STATUS_WORD DW 0 +RES_AREA DB 0,0,0,0,0,0,0,0 +OP_DATA DB 0 +REQUEST_HEADER ENDS +; +; Initialize command request header structure +; +INIT_HEADER STRUC + DB 13 DUP (?) +NUM_UNITS DB 0 +BRK_ADDR DD 0 +ARG_PTR DD 0 +DRV_NUM DB 0 +INIT_HEADER ENDS +BRK_OFF EQU WORD PTR BRK_ADDR +BRK_SEG EQU WORD PTR BRK_ADDR+2 +ARG_OFF EQU WORD PTR ARG_PTR +ARG_SEG EQU WORD PTR ARG_PTR+2 +; +; Media check request header structure +; +MEDIA_HEADER STRUC + DB 13 DUP (?) +MEDIA_BYTE DB 0 +RET_BYTE DB 0 +VOL_PTR DD 0 +MEDIA_HEADER ENDS +VOL_OFF EQU WORD PTR VOL_PTR +VOL_SEG EQU WORD PTR VOL_PTR+2 +; +; Build BPB request header structure +; +BPB_HEADER STRUC + DB 13 DUP (?) +BPB_DESC DB 0 +BPB_TRANS DD 0 +TABLE_PTR DD 0 +BPB_HEADER ENDS +BPB_OFF EQU WORD PTR BPB_TRANS +BPB_SEG EQU WORD PTR BPB_TRANS+2 +TABLE_OFF EQU WORD PTR TABLE_PTR +TABLE_SEG EQU WORD PTR TABLE_PTR+2 +; +; Input/output request header structure +; +IO_HEADER STRUC + DB 13 DUP (?) +IO_DESC DB 0 +IO_TRANS DD 0 +IO_COUNT DW 0 +IO_START DW 0 +VOL_ID DD 0 +IO_HEADER ENDS +IO_OFF EQU WORD PTR IO_TRANS +IO_SEG EQU WORD PTR IO_TRANS+2 +ID_OFF EQU WORD PTR VOL_ID +ID_SEG EQU WORD PTR VOL_ID+2 +; +; Device driver BIOS Parameter Block (BPB) structure +; +BPB_BLOCK STRUC +BYTES_PER_SECTOR DW 0 +SECTORS_PER_ALLOC DB 0 +RES_SECTORS DW 0 +NUM_FATS DB 0 +ROOT_DIR_ENTRIES DW 0 +NUMBER_OF_SECTORS DW 0 +MEDIA_DESC DB 0 +SECTORS_PER_FAT DW 0 +BPB_BLOCK ENDS +; +; Device driver BIOS Parameter option block structure +; +BPB_OPTION STRUC +SECTORS_PER_TRACK DW 0 +NUMBER_OF_HEADS DW 0 +HIDDEN_SECTORS DW 0 +BPB_OPTION ENDS + +.list ; end of DRIVER.STR diff --git a/v4.0/src/MEMM/MEMM/EKBD.ASM b/v4.0/src/MEMM/MEMM/EKBD.ASM new file mode 100644 index 0000000..9f8a8f2 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EKBD.ASM @@ -0,0 +1,139 @@ + + + page 58,132 +;****************************************************************************** + title EKBD - get keyboard make codes +;****************************************************************************** +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EKBD - basic keyboard handler for error handler routine +; +; Version: 0.04 +; +; Date : June 10,1986 +; +; Author: +; +;****************************************************************************** +; +; CHANGES: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------ +; 06/10/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/06/86 0.04 Changed assumes to DGROUP +; +;****************************************************************************** +; +; Functional description: Return keyboard code while ignoring any break +; or command codes. +; +;****************************************************************************** + page +.386P +; + include vdmseg.inc + include kbd.inc +;****************************************************************************** +; Public Declarations +;****************************************************************************** +; + public egetc ; get a character + public WaitKBD ; wait for keyboard ready +;****************************************************************************** +; Externs +;****************************************************************************** +_TEXT segment +_TEXT ends + +_DATA segment +_DATA ends +; +;****************************************************************************** +; Equates +;****************************************************************************** +; +; +;****************************************************************************** +; LOCAL DATA +;****************************************************************************** +_DATA segment +_DATA ends +; +;****************************************************************************** +; +; egetc - read a character from keyboard +; +; entry: NONE +; +; exit: al = make code +; ZF = 0 +; +; or ZF = 1 if no code available +; +; used: none +; +; stack: +; +;****************************************************************************** +_TEXT segment + ASSUME CS:_TEXT, DS:DGROUP, ES:DGROUP +egetc proc near +; + in al,KbStatus ; get status + test al,1 ; q: is there anything out there? + jz kret ; n: return +; ; y: disable keyboard + call WaitKBD ; wait til 8042 ready for input + mov al,0adh ; disable keyboard interface + out KbStatus,al + in al,KbData ; get character + cmp al,7fh ; q: break or control word? + jae ign_chr ; y: ignore it + cmp al,80h ; clear ZF + jmp enaKB ; go enable keyboard +ign_chr: + mov al,0 ; return an invalid character + ; but preserve ZF +enaKB: + pushf ; save flags + push ax ; save character + call WaitKBD + mov al,0aeh ; enable keyboard + out KbStatus,al + pop ax + popf +kret: + ret +egetc endp +; +;****************************************************************************** +; +; WaitKBD - wait for status to indicate ready for new command +; +; entry: NONE +; +; exit: NONE +; +; used: al +; +; stack: +; +;****************************************************************************** +WaitKBD proc near + push cx + xor cx,cx ; do 65536 times +wait: + in al,KbStatus + test al,BufFull ; q: busy? + loopnz wait ; y: try again +; + pop cx ; n: return + ret +WaitKBD endp + +_TEXT ENDS + END diff --git a/v4.0/src/MEMM/MEMM/ELIM.INC b/v4.0/src/MEMM/MEMM/ELIM.INC new file mode 100644 index 0000000..47f0bc0 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ELIM.INC @@ -0,0 +1,128 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: ELIM.INC - include for LIM I/O traps (DMA ports) +; +; Version: 0.03 +; +; Date: April 9, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/09/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/01/86 0.03 DMA trapping related equates added +; +; DATE AUTHOR DESCRIPTION +; ------- -------- ------------------------------------------------------- +; 06/21/88 ISP Removed the Intel Above Board Port Definitions +; 07/27/88 JHB Added Channel 4 ports, ports for Mode Regs and changed +; DMARegRec and DMARegBuf structure definitions - lifted +; from vdmad.inc in Win386/2.03. +; - Jaywant H Bharadwaj +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif +; +; +; DMA related ports +; +DMA_P0 equ 0087h ; DMA page register for Channel 0 +DMA_P1 equ 0083h ; DMA page register for Channel 1 +DMA_P2 equ 0081h ; DMA page register for Channel 2 +DMA_P3 equ 0082h ; DMA page register for Channel 3 +DMA_P5 equ 008Bh ; DMA page register for Channel 5 +DMA_P6 equ 0089h ; DMA page register for Channel 6 +DMA_P7 equ 008Ah ; DMA page register for Channel 7 +DMA_P4 equ 0080h ; dummy page reg for channel 4 + +DMA_B0 equ 0000h ; DMA base register for Channel 0 +DMA_C0 equ 0001h ; DMA count register for Channel 0 +DMA_B1 equ 0002h ; DMA base register for Channel 1 +DMA_C1 equ 0003h ; DMA count register for Channel 1 +DMA_B2 equ 0004h ; DMA base register for Channel 2 +DMA_C2 equ 0005h ; DMA count register for Channel 2 +DMA_B3 equ 0006h ; DMA base register for Channel 3 +DMA_C3 equ 0007h ; DMA count register for Channel 3 +DMA_B4 equ 00C0h ; DMA base register for Channel 4 +DMA_C4 equ 00C2h ; DMA count register for Channel 4 +DMA_B5 equ 00C4h ; DMA base register for Channel 5 +DMA_C5 equ 00C6h ; DMA count register for Channel 5 +DMA_B6 equ 00C8h ; DMA base register for Channel 6 +DMA_C6 equ 00CAh ; DMA count register for Channel 6 +DMA_B7 equ 00CCh ; DMA base register for Channel 7 +DMA_C7 equ 00CEh ; DMA count register for Channel 7 + +DMA1_CLR_FF equ 000Ch ; clear flip-flop cmd for channels 0-3 +DMA2_CLR_FF equ 00D8h ; clear flip-flop cmd for channels 5-7 + + +DMA1_MODE equ 000Bh ; Mode register for channels 0-3 +DMA2_MODE equ 00D6h ; Mode register for channels 4-7 + +DMA_M_CHANNEL equ 03h ; Mask for channel +DMA_M_OPERATION equ 0Ch ; Mask for operation +DMA_M_16BIT equ 040h ; 16bit transfers (PS/2 ext mode) + +DMA_M_VERIFY equ 0 ; Verify operation +DMA_M_WRITE equ 4 ; Write + + +;************************************************************************** +; New defintions for DMARegRec and DMARegBuf - 7/27/88 +; +; +; DMA Register Save Structure +; + +; +; note: the DMA code in ELIMTRAP.ASM is tuned to this structure's size = 16 +; if you change the size, you had better change the code ! +; LinAdr and PhysAdr have to be dwords +; count though 16 bits long is left as a dword since the rest of the ported +; 386 code is dependent on this structure being 16 bytes long. +; + +DMARegRec struc +DMALinAdr dd 00000000 ; Channel Linear Base Register +DMAPhyAdr dd 00000000 ; Channel Physical Base Register +DMACount dd 00000000 ; Channel Count Register +DMAPagePort db ? ; byte addr of page reg +DMABasePort db ? ; byte addr of base addr reg +DMACntPort db ? ; byte addr of cnt addr reg +DMAMode db ? ; Mode register +DMARegRec ends + +DMARegBuf struc +Chnl0 db (size DMARegRec - 4) dup (00), DMA_P0, DMA_B0, DMA_C0, 0 +Chnl1 db (size DMARegRec - 4) dup (00), DMA_P1, DMA_B1, DMA_C1, 0 +Chnl2 db (size DMARegRec - 4) dup (00), DMA_P2, DMA_B2, DMA_C2, 0 +Chnl3 db (size DMARegRec - 4) dup (00), DMA_P3, DMA_B3, DMA_C3, 0 +Chnl4 db (size DMARegRec - 4) dup (00), DMA_P4, DMA_B4, DMA_C4, DMA_M_16BIT +Chnl5 db (size DMARegRec - 4) dup (00), DMA_P5, DMA_B5, DMA_C5, DMA_M_16BIT +Chnl6 db (size DMARegRec - 4) dup (00), DMA_P6, DMA_B6, DMA_C6, DMA_M_16BIT +Chnl7 db (size DMARegRec - 4) dup (00), DMA_P7, DMA_B7, DMA_C7, DMA_M_16BIT +DMAFF1 db 00 ; Controller 1 FlipFlop State +DMAFF2 db 00 ; Controller 2 FlipFlop State +DMA_Xfun db 0 ; Extended Operation Function +DMA_Xchn db 0 ; Extended Operation Channel +DMARegBuf ends + +DMAREG_CTRL2_INDEX equ 4 * 2 ; 2 * 1st channel # on 2nd cntlr + + +.list ; end of ELIM.INC + diff --git a/v4.0/src/MEMM/MEMM/ELIMFUNC.ASM b/v4.0/src/MEMM/MEMM/ELIMFUNC.ASM new file mode 100644 index 0000000..d431f0b --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ELIMFUNC.ASM @@ -0,0 +1,268 @@ + + + page 58,132 +;****************************************************************************** + title ELIMFUNC - MEMM functions module +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: ELIMFUNC - entry point for VDM functions +; +; Version: 0.05 +; +; Date: May 24,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 04/24/86 Original From EMML LIM driver. +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/05/86 0.04 Added segment R_CODE +; 07/06/86 0.04 Changed assume to DGROUP +; 07/10/86 0.05 jmp $+2 before "POPF" +; +;****************************************************************************** +; Functional Description: +; This module contains the ON/OFF functionality code for activating/ +; deactivating EMM386 from DOS. Functions in _TEXT to reduce code in +; R_CODE segment. +; +;****************************************************************************** +.lfcond +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public ELIM_Entry + public EFunTab + public EFUN_CNT +; + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include vdmseg.inc + +FALSE equ 0 +TRUE equ not FALSE + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +_DATA segment + extrn Active_Status:byte + extrn Auto_Mode:byte +_DATA ends + +_TEXT segment + extrn _AutoUpdate:near ; update auto mode status + extrn GoVirtual:near + extrn RRProc:near ; Return processor to real mode(RRTrap) +_TEXT ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +;****************************************************************************** +; +; Code Segment R_CODE +; +;****************************************************************************** +; +R_CODE segment + assume cs:R_CODE, ds:DGROUP, es:DGROUP +; +; ELIM functions table - far calls +; +EFunTab label dword + dw offset E_GetStatus + dw seg _TEXT + + dw offset E_ONOFF + dw seg _TEXT + +EFUN_CNT equ ($-EFunTab)/4 + + page +;****************************************************************************** +; ELIM_Entry - entry point for general ELIM functions +; +; THIS IS A FAR CALL ROUTINE +; +; ENTRY: REAL or VIRTUAL mode only +; AH = 0 => get current status of VDM/EMM386 +; AH = 1 => ON/OFF/AUTO +; +; EXIT: EMM386 is activated/deactivated if possible +; NC => no errors. +; CY => ERROR occured. +; AH = error number +; AH= 01 =>invalid function. +; +; USED: none +; +;****************************************************************************** +ELIM_Entry proc far +; + push bx + push ds +; + mov bx,seg DGROUP + mov ds,bx +; + cmp ah,EFUN_CNT ;Q: valid function # + jae EE_inv_func ; N: return error + xor bx,bx ; Y: exec function + mov bl,ah ; bx = function # + shl bx,2 ; dword index + call CS:EFunTab[bx] ; call the function +; +EE_exit: + pop ds + pop bx + ret +; +EE_inv_func: + mov ah,01 + stc + jmp short EE_exit +; +ELIM_Entry endp + +R_CODE ends + + page +;****************************************************************************** +; +; Code Segment _TEXT +; +;****************************************************************************** +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP + +;****************************************************************************** +; E_GetStatus - get ELIM/VDM status +; +; ENTRY: AH = 0 +; DS = DGROUP +; +; EXIT: AH = 0 => ELIM ON +; = 1 => ELIM OFF +; = 2 => ELIM in AUTO mode (ON) +; = 3 => ELIM in AUTO mode (OFF) +; +; USED: none +; +;****************************************************************************** +E_GetStatus proc far +; + xor ah,ah ; init to on + cmp [Auto_Mode],0 ; Q: auto mode ? + je not_auto ; N: try on/off + mov ah,2 ; Y: indicate as such +not_auto: + cmp [Active_Status],0 ;Q: is ELIM active ? + jne EGS_exit ; Y: exit with status = 0/2 + inc ah ; N: exit with status = 1/3 +EGS_exit: + ret +; +E_GetStatus endp + +;****************************************************************************** +; E_ONOFF - general ON/OFF code for ELIM +; +; ENTRY: AH = 1 +; AL = 0 => ON +; AL = 1 => OFF +; AL = 2 => AUTO +; DS = DGROUP +; +; EXIT: Virtual mode and ELIM ON +; OR Real mode and ELIM OFF +; +; USED: none +; +;****************************************************************************** +E_ONOFF proc far +; + cmp al,0 ;Q: turn it on ? + jne EOO_OFF ; N: check for OFF/AUTO + cmp [Active_Status],0 ; Y: Q: is it already active ? + jne EOO_AUTO_OFF ; Y: then just leave + mov [Active_Status],1 ; N: then go to virtual mode + mov [Auto_Mode],0 ; and clear auto mode + call GoVirtual + jmp short EOO_OK +EOO_OFF: + cmp al,1 ;Q: turn it off ? + jne EOO_AUTO ; N: check for AUTO mode + +; +; we are not providing the ability to turn emm off. +; +; cmp [Active_Status],0 ; Y: Q: is it already OFF ? +; je EOO_AUTO_OFF ; Y: then just leave +; mov [Active_Status],0 ; N: then go to real mode +; mov [Auto_Mode],0 ; and clear auto mode +; call RRProc ; put processor in real mode +; jmp short EOO_OK + + jmp short EOO_inv + + +EOO_AUTO_OFF: +; cmp [Auto_Mode],0 ; q: auto mode already off? +; jz EOO_OK ; y: forget it +; mov [Auto_Mode],0 ; n: clear it +; jmp short EOO_OK ; and update status + + jmp short EOO_inv + + +EOO_AUTO: + cmp al,2 ;Q: go to auto mode ? + jne EOO_inv ; N: invalid function +; cmp [Auto_Mode],0 ; Y: Q: is it already in auto mode +; jne EOO_OK ; Y: then just leave +; mov [Auto_Mode],1 ; N: then go to auto mode +; call _AutoUpdate ; + + jmp short EOO_inv +; +; leave with no errors +; +EOO_OK: + clc + +EOO_exit: + ret +; +; invalide ON/OFF/AUTO function call +; +EOO_inv: + mov ah,1 + stc + jmp short EOO_exit +; +E_ONOFF endp + +; +_TEXT ends + + end + diff --git a/v4.0/src/MEMM/MEMM/ELIMTRAP.ASM b/v4.0/src/MEMM/MEMM/ELIMTRAP.ASM new file mode 100644 index 0000000..1036c33 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ELIMTRAP.ASM @@ -0,0 +1,1560 @@ + + +;****************************************************************************** + title DMATRAP.ASM - Trap handlers for DMA ports +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: DMATRAP.ASM - Trap Handlers for DMA ports +; +; Version: 0.04 +; +; Date: April 9, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/09/86 Original +; 06/18/86 0.01 Modified LIM_Map to handle all 4 boards and call +; page mapping routine in EMMLIB.LIB +; 06/27/86 0.02 Made _page_frame_address indexing dword (was word) +; +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/01/86 0.03 Added DMA support routines +; 07/02/86 0.03 Fixed CNT size vs. length problem +; 07/06/86 0.04 Made _pft386 a ptr to _pft386 array +; 07/06/86 0.04 now sets _window array also +; 08/11/86 0.05 moved IO_Trap code for LIM DMA trapping here +; 06/09/88 remove IOT_LIM, LIMMap, and InitELIM since we don't +; have any EMM hardware to trap and emulate now (Paulch) +; 07/26/88 reintroduced initelim removing iab port trap (ISP) +; +; 07/27/88 Started rewriting the DMA port trap handlers - similar to the +; code in VDMAD.ASM in Win/386 V2.03 +; - Jaywant H Bharadwaj +; +;***************************************************************************** + + +;****************************************************************************** +; +; Functional Description: +; +; Monitors writes/reads to the DMA ports. +; Reads are simple - return the value saved in DMARegSav structure. +; On a write to Page/Base/count Reg port - +; user specifies a linear address. DMAs can handle only physical addresses. +; Therefore, the actual physical address has to be written into the Page and +; base Address Reg. Also the DMA transfer area may not be physically contiguous. +; If it isn't we should remap the linear address so that it is physically +; contiguous. +; +; We never know when a DMA is started. Hence on every access to the Page/Base +; or count Register we make sure that the linear address specified by the user +; maps to a physical address which is contiguous over the DMA transfer area. +; This has to be done even if the count register is altered since the user +; might be relying on the previous contents of Page/Addr Regs which may not be +; contiguous anymore. +; +; All routines except InitDMA are entered through protected mode only. +; +;****************************************************************************** + +.lfcond ; list false conditionals +.386p + + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** + +; +; routines called from C +; + public _GetPte + public _SetPte + public _GetCRSEntry + public _GetDMALinAdr + public _Exchange16K + public _FatalError + + public InitELIM ; initialization routine for LIMulator + public InitDMA ; init DMA register save area + public DMARegSav + public _DMA_Pages + public DMA_Pages + public _DMA_PAGE_COUNT + public DMA_PAGE_COUNT + + + + public DMA_DMAFixup + public DMABase0 + public DMABase1 + public DMABase2 + public DMABase3 + public DMABase5 + public DMABase6 + public DMABase7 + + public DMACnt0 + public DMACnt1 + public DMACnt2 + public DMACnt3 + public DMACnt5 + public DMACnt6 + public DMACnt7 + public DMAPg0 + public DMAPg1 + public DMAPg2 + public DMAPg3 + public DMAPg5 + public DMAPg6 + public DMAPg7 + public DMAClrFF1 + public DMAClrFF2 + public DMAMode1 + public DMAMode2 + + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + include elim.inc + include mach_id.inc + include page.inc + include oemdep.inc + include instr386.inc + include vm386.inc + include emmdef.inc + +;****************************************************************************** +; +; 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 + +;**************************************************************************** +; +; InitDMARegSav - MACRO for initialising save area for channels +; +; ENTRY: chan_num = channel number (1,2,3,5,6,7) +; ES -> DGROUP +; +;----------------------------------------------------------------------------- + +InitDMARegSav MACRO chan_num + + lea di,[DMARegSav.Chnl&chan_num] ; pt to channel's save area + + xor eax, eax + in al,DMA_P&chan_num ; page register for channel + jmp $+2 + jmp $+2 ; timing + shl eax,16 ; high EAX = high word of linear addr + + ; flip-flop already reset by the caller + + in al,DMA_B&chan_num ; get low byte of base + jmp $+2 + jmp $+2 ; timing + mov ah,al + in al,DMA_B&chan_num ; get high byte of base + xchg ah,al + ; EAX = LINEAR BASE address + + stosd ; store LINEAR BASE address + + stosd ; store PHYSICAL BASE address + + xor eax, eax ; clear EAX + jmp $+2 + jmp $+2 ; timing + in al,DMA_C&chan_num ; get low byte of count + jmp $+2 + jmp $+2 ; timing + mov ah,al + in al,DMA_C&chan_num ; get high byte of count + xchg ah,al + ; EAX = count + + stosd ; store count + + add di, 4 ; skip 4 bytes - 3 ports+mode byte + + ENDM + + +;****************************************************************************** +; DMA_WADDR_TO_BADDR - convert internal DMA word address to a byte address +; +; ENTRY: 386 PROTECTED MODE +; DS -> DGROUP +; ES -> DGROUP +; EAX - Word Address +; +; EXIT: EAX - Byte address +; +; USED: +;------------------------------------------------------------------------------ +DMA_WADDR_TO_BADDR MACRO + LOCAL Not_AT + + cmp [ROM_BIOS_Machine_ID], RBMI_Sys80 + jbe short Not_AT ; If running on EBIOS machine + + ror eax,16 ; AX = high word + shr al,1 ; adjust for D0 null in page reg + rol eax,17 ; EAX = address w/ adjust for + ; 'A0' offset +Not_At: + shl ecx, 1 ; Adjust for word units + ENDM + + +;****************************************************************************** +; DMA_BADDR_TO_WADDR - convert internal DMA byte address to a word address +; +; ENTRY: 386 PROTECTED MODE +; DS -> DGROUP +; ES -> DGROUP +; EAX - Word Address +; +; EXIT: EAX - Byte address +; +; USED: +;------------------------------------------------------------------------------ +DMA_BADDR_TO_WADDR MACRO + LOCAL Not_AT + + cmp [ROM_BIOS_Machine_ID], RBMI_Sys80 + jbe short Not_AT ; If running on EBIOS machine + + shr eax, 1 ; Adjust for implied 'A0' + push ax ; Save A16-A1 + xor ax, ax + shl eax, 1 ; Adjust for unused Pg Reg D0 + pop ax ; Restore A16-A1 +Not_At: + ENDM + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** + +_DATA segment +extrn ROM_BIOS_Machine_ID:byte +extrn _page_frame_base:word +extrn CurRegSet:word +extrn Page_Dir:word +SaveAL db ? +_DATA ends + +_TEXT segment + +extrn PortTrap:near ; set port bit in I/O bit Map +extrn MapLinear:near +extrn ErrHndlr:near +; +; Swap pages so that DMA Xfer area is physically contiguous. +; defined in mapdma.c +; +extrn _SwapDMAPages:near + +_TEXT ends + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +_DATA segment + +DMARegSav DMARegBuf <> ; DMA Register buffer + +DMAP_Page label word +; dw DMA_P0 ; DMA page registers + dw DMA_P1 + dw DMA_P2 + dw DMA_P3 + dw DMA_P5 + dw DMA_P6 + dw DMA_P7 +; dw DMA_P4 +; dw DMA_P0+10h ; page regs mapped to here also + dw DMA_P1+10h + dw DMA_P2+10h + dw DMA_P3+10h + dw DMA_P5+10h + dw DMA_P6+10h + dw DMA_P7+10h +; dw DMA_P4+10h +DMAP_Addr label word +; dw DMA_B0 ; DMA base registers + dw DMA_B1 + dw DMA_B2 + dw DMA_B3 + dw DMA_B5 + dw DMA_B6 + dw DMA_B7 +DMAP_Count label word +; dw DMA_C0 ; DMA count registers + dw DMA_C1 + dw DMA_C2 + dw DMA_C3 + dw DMA_C5 + dw DMA_C6 + dw DMA_C7 + dw DMA1_CLR_FF ; reset flip-flop commands + dw DMA2_CLR_FF +DMAP_Mode label word + dw DMA1_MODE + dw DMA2_MODE + +LIMDMAP_CNT = ($ - DMAP_Page) / 2 +; +; DMA_Pages - EMM Pages for DMA relocation. Each is an index into pft386. +; To access actual entry in pft386 you need to multiply index by 4. +; If eight contingous 16k EMM pages are not available - the unavailable +; entries are left at NULL_PAGE. +; This array should be initialized at boot time. +; +_DMA_Pages LABEL WORD +DMA_Pages dw 8 dup (NULL_PAGE) ; null for start +_DMA_PAGE_COUNT LABEL WORD +DMA_PAGE_COUNT dw 0 ; number of above initialised + + +_DATA ends + + page + +;------------------------------------------------------------------------------ + +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP + +;****************************************************************************** +; +; InitDMA - initialize internal values for DMA registers of each channel +; +; ENTRY: Real Mode +; DS = DGROUP +; +; EXIT: Real Mode +; DGROUP:[DMARegSav] = DMA register save area initialized +; +;------------------------------------------------------------------------------ + +InitDMA proc near + + push eax + push di + push es + + pushf + cli + cld + + push ds + pop es ; ES = DGROUP + + xor al,al + out DMA1_CLR_FF, al ; clear FF on first controller + mov [DMARegSav.DMAFF1], al ; reset S/W FF + jmp $+2 + jmp $+2 ; timing +; +; initialize regs for channels 1,2,3 +; + InitDMARegSav 1 + InitDMARegSav 2 + InitDMARegSav 3 + + xor al,al + out DMA2_CLR_FF, al ; clear FF on second controller + mov [DMARegSav.DMAFF2], al ; reset S/W FF + jmp $+2 + jmp $+2 ; timing +; +; initialize regs for channels 5,6,7 +; + InitDMARegSav 5 + InitDMARegSav 6 + InitDMARegSav 7 + + popf + pop es + pop di + pop eax + ret + +InitDMA endp + +;****************************************************************************** +; +; DMABase(0-7) - Write/Read DMA Channel N Base Register +; +; ENTRY: +; AL = byte to output to port +; BX = port * 2 +; DH = 0 => Emulate Input +; <>0 => Emulate Output +; +; EXIT: +; AL = emulated input/output value from port. +; CLC => I/O emulated or performed +; +;------------------------------------------------------------------------------ +DMABase0to7 proc near + +DMABase4: ; I/O port C0h +DMABase5: ; I/O port C4h +DMABase6: ; I/O port C8h +DMABase7: ; I/O port CCh + push ax + push bx + push cx + push dx + push si +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg dx, bx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + mov si, dx + sub si, 0B0h ; SI = Channel * 4 + shl si, 2 ; SI = Channel * 16 + mov bl, [DMARegSav.DMAFF2] ; get flip-flop + xor [DMARegSav.DMAFF2], 1 ; and toggle it + jmp short DMABaseN ; + +DMABase0: ; I/O port 00h +DMABase1: ; I/O port 02h +DMABase2: ; I/O port 04h +DMABase3: ; I/O port 06h + push ax + push bx + push cx + push dx + push si +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg dx, bx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + mov si, dx ; SI = Channel * 2 + shl si, 3 ; SI = Channel * 16 + mov bl, [DMARegSav.DMAFF1] ; get flip-flop + xor [DMARegSav.DMAFF1], 1 ; and toggle it + +; +; FALL THROUGH!!! +; + +;****************************************************************************** +; +; DMABaseN - Write/Read DMA Channel N Base Register +; +; ENTRY: As above plus +; SI = 16 * channel # +; +;------------------------------------------------------------------------------ +DMABaseN: + and bl, 1 ; Look at bit0 only - safety + + or bh,bh ;Q: Input ? + jz short Base_rd_port ; Y: do Read operation + ; N: save value "written" + mov [SaveAL], al ; save AL in Save area. + xor bh, bh ; Make BX = Flip Flop state + mov byte ptr DMARegSav.DMALinAdr[bx][si], al + + in al, dx ; Just a Dummy I/O to + ; toggle the real flip-flop + ; to match DMAFF above + jmp $+2 + jmp $+2 + xor bl,1 ; and the s/w one + + call DMA_DMAFixup ; Translate Lin to Phys + ; & Update DMARegSav + call DMA_WrtAdrReg ; emulate the write + jmp short DBExit + +Base_rd_port: + in al, dx ; Toggle the real flop-flip +; +; bh is already zero, therefore BX = flip flop state +; + mov al,byte ptr DMARegSav.DMALinAdr[bx][si] + mov [SaveAL], al +DBExit: + pop si + pop dx + pop cx + pop bx + pop ax + mov al, [SaveAL] + clc + ret + +DMABase0to7 endp + + page + +;****************************************************************************** +; +; DMACnt(0-7) - Write/Read DMA Channel N Count Register +; +;ENTRY: +; AL = byte to output to port. +; BX = port * 2 +; DH = 0 => Emulate Input. +; <>0 => Emulate Output. +; +;EXIT: +; AL = emulated input/output value from port. +; CLC => I/O emulated or performed +; +;------------------------------------------------------------------------------ + +DMACnt0to7 proc near + +DMACnt4: ; I/O port C2h +DMACnt5: ; I/O port C6h +DMACnt6: ; I/O port CAh +DMACnt7: ; I/O port CEh + push ax + push bx + push cx + push dx + push si +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg dx, bx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + mov si, dx + sub si, 0B2h ; SI = 4 * channel # + shl si, 2 ; si = 16 * channel # + mov bl, [DMARegSav.DMAFF2] ; get flip-flop + xor [DMARegSav.DMAFF2], 1 ; toggle our flip-flop + jmp short DMACntN + +DMACnt0: ; I/O port 01h +DMACnt1: ; I/O port 03h +DMACnt2: ; I/O port 05h +DMACnt3: ; I/O port 07h + push ax + push bx + push cx + push dx + push si +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg dx, bx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + mov si, dx + dec si + shl si, 3 ; si = 16 * channel # + mov bl, [DMARegSav.DMAFF1] ; get flip-flop + xor [DMARegSav.DMAFF1], 1 ; toggle our flip-flop +; +; FALL THROUGH!!! +; + +;****************************************************************************** +; +; DMACntN - Write/Read DMA Channel N Count Register +; +; ENTRY: As DMACnt1to7 plus +; si = 16 * channel # +; +;------------------------------------------------------------------------------ +DMACntN: + and bl, 1 ; Look at bit0 only - Safety + + or bh,bh ;Q: Input ? + jz short DMA_CntN_rd ; Y: do Read operation + ; N: save value "written" + mov [SaveAL], al ; save AL in Save area. + xor bh, bh ; make BX = Flip Flop state + mov byte ptr DMARegSav.DMACount[bx][si], al ; save cnt + out dx, al ; do the I/O + + xor bl,1 ; Toggle flip-flop for Wrt + call DMA_DMAFixup ; Translate Lin to Phys + ; & Update DMARegSav + call DMA_WrtAdrReg ; emulate the write + call DMALoadCount + + jmp short DCExit +DMA_CntN_rd: + xor bh,bh ; make BX = Flip Flop state + in al, dx ; Toggle the real flip-flop + ; to match bx above + mov [SaveAL], al + + jmp $+2 + jmp $+2 + xor bl,1 ; and the s/w one +; +; get current count values from cntlr +; + in al, dx ; get 2nd byte of Count reg + jmp $+2 ; timing ... + jmp $+2 ; timing ... + mov byte ptr DMARegSav.DMACount[bx][si], al ; save it + xor bl, 1 ; flip to other byte + in al, dx ; get 1st byte of Count reg + mov byte ptr DMARegSav.DMACount[bx][si], al ; save it +DCExit: + pop si + pop dx + pop cx + pop bx + pop ax + mov al, [SaveAL] + + clc ; I/O emulated, return + ret + +DMACnt0to7 endp + + page +;****************************************************************************** +; +; DMAPgN - Write/Read DMA Channel N Page Register +; +; ENTRY: +; AL = byte to output to port +; BX = port * 2 +; DX = 0 => Emulate Input +; <>0 => Emulate Output +; si = 2 * Channel # +; +; EXIT: +; AL = emulated input/output value from port. +; CLC => I/O emulated or performed +; +; USED: EBX,Flags +; STACK: +; +; NOTES: For channels 0-4, DMACount is in Bytes, and +; DMALinAdr holds the address as: +; +; +-----------+-----------+----------------------+ +; | 31-24 | 23-16 | 15-0 | +; +-----------+-----------+----------------------+ +; | 0000 0000 | A23-A16 | A15-A0 | +; +-----------+-----------+----------------------+ +; +; For channels 5-7, DMACount is in Words, and +; DMALinAdr holds the address as: +; +; +-----------+-----------+----------------------+ +; | 31-24 |23-17 | 16 | 15-0 | +; +-----------+-----------+----------------------+ +; | 0000 0000 |A23-A17 |0 | A16-A1 | +; +-----------+-----------+----------------------+ +; +; +;------------------------------------------------------------------------------ +DMAPg0to7 proc near + +DMAPg0: + push si + mov si,0*16 ; si = 16 * channel # + jmp short DMAPgN +DMAPg1: + push si + mov si,1*16 ; si = 16 * channel # + jmp short DMAPgN +DMAPg2: + push si + mov si,2*16 ; si = 16 * channel # + jmp short DMAPgN +DMAPg3: + push si + mov si,3*16 ; si = 16 * channel # + jmp short DMAPgN +DMAPg5: + push si + mov si,5*16 ; si = 16 * channel # + jmp short DMAPgN +DMAPg6: + push si + mov si,6*16 ; si = 16 * channel # + jmp short DMAPgN +DMAPg7: + push si + mov si,7*16 ; si = 16 * channel # +; FALL THROUGH + +;---------------------------------------------------------------------- +; DMAPgN - Common Page Code +; +; ENTRY: As above plus +; si = 16 * Channel # +; +;---------------------------------------------------------------------- + +DMAPgN: + push ax + push bx + push cx + push dx +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg dx, bx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + or bh,bh ;Q: Input ? + jz short Pg_rd_port ; Y: do Read operation + + mov [SaveAL], al ; save AL in Save area. +; +; Get s/w FF for WrtAdrReg +; + mov bl, [DMARegSav.DMAFF1] ; Assume Chan 1 FF + cmp si, 4*16 ; Q: Addr for 2nd controller + jb short PgN_FF ; A: No, FF is correct + mov bl, [DMARegSav.DMAFF2] ; Chan 2 FF +PgN_FF: + xor bh, bh ; make BX = flip-flop state + + mov byte ptr DMARegSav.DMALinAdr.HighWord[si], al ; save value + call DMA_DMAFixup ; Translate Lin to Phys + ; & Update DMARegSav + call DMA_WrtAdrReg ; emulate the write + jmp short DPExit +Pg_rd_port: + mov al, byte ptr DMARegSav.DMALinAdr.HighWord[si] + mov [SaveAL], al +DPExit: + pop dx + pop cx + pop bx + pop ax + pop si + mov al, [SaveAL] + clc + ret + +DMAPg0to7 endp + + page + +;****************************************************************************** +; +; DMAClrFF1 - Reset Controller 1's FlipFlop +; DMAClrFF2 - Reset Controller 2's FlipFlop +; +; ENTRY: +; AL = byte to output to port. +; BX = port * 2 +; DH = 0 => Emulate Input. +; <>0 => Emulate Output. +; +; EXIT: +; AL = emulated input/output value from port. +; CLC => I/O emulated or performed +; +;------------------------------------------------------------------------------ + +DMAClrFF1 proc near + push ax + push bx + push cx + push dx +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg bx, dx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + or bh,bh ;Q: Input ? + jz short DMA_CLF_RdEm ; Y: Let it go + out dx, al ; N: do it + mov [DMARegSav.DMAFF1], 0 + jmp short DMACFFexit +DMA_CLF_RdEm: + in al,dx ; do the read +DMACFFexit: + pop dx + pop cx + pop bx + pop ax + clc + ret + +DMAClrFF1 endp + +DMAClrFF2 proc near + + push ax + push bx + push cx + push dx +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg bx, dx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + or bh,bh ;Q: Input ? + jz DMA_CLF_RdEm ; Y: Let it go + out dx, al ; N: do it + mov [DMARegSav.DMAFF2], 0 + jmp DMACFFexit + +DMAClrFF2 endp + + page +;****************************************************************************** +; +; DMAMode1 - Track Controller 1's Mode Register +; DMAMode2 - Track Controller 2's Mode Register +; +; ENTRY: +; AL = byte to output to port. +; BX = port * 2 +; DX = 0 => Emulate Input. +; <>0 => Emulate Output. +; +; EXIT: +; AL = emulated input/output value from port. +; CLC => I/O emulated or performed +; +;------------------------------------------------------------------------------ + +DMAMode1 proc near + push ax + push bx + push cx + push dx + push si +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg bx, dx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + or bh,bh ;Q: Input ? + jz short DMA_Mread ; Y: Let it go + + mov [SaveAL], al ; save AL in Save area. + xor ah, ah + mov si, ax + and si, DMA_M_CHANNEL + mov bl, al + and bl, NOT DMA_M_16BIT ; 8 bit xfers for controller 1 +DMA_Mboth: + shl si, 4 ; Channel * 16 + mov [DMARegSav.DMAMode][si], bl + out dx, al ; N: do it + jmp short DMExit + +DMA_Mread: + in al, dx ; do the read + mov [SaveAL], al +DMExit: + pop si + pop dx + pop cx + pop bx + pop ax + mov al, [SaveAL] + clc + ret +DMAMode1 endp + +DMAMode2 proc near + + push ax + push bx + push cx + push dx + push si +; +; Now, BX = port * 2 and DX = IO code +; Code ported from Win/386 expects DX = port and BH = IO code +; + xchg bx, dx + shr dx, 1 + xchg bh,bl ; move IO code to bh + + or bh,bh ;Q: Input ? + jz DMA_Mread ; Y: Let it go + + mov [SaveAL], al ; save AL in Save area. + xor ah, ah + mov si, ax + and si, DMA_M_CHANNEL + add si, 4 ; Channel 4 to 7 + mov bl, al + or bl, DMA_M_16BIT ; 16 bit for controller 2 + jmp DMA_Mboth + +DMAMode2 endp + +; INCLUDE VDMAD2.ASM + + page +;****************************************************************************** +;DMA_GetLinAdr - return Linear Address, count and mode from DMARegSave area +; +; ENTRY: +; si = channel # * 16 +; DS assume DGROUP +; +; EXIT: +; EAX = linear Base Address +; ECX = SIZE of transfer (bytes) +; DL = Mode register +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +DMA_GetLinAdr proc near + + mov eax, dword ptr DMARegSav.DMALinAdr[si] + mov ecx, dword ptr DMARegSav.DMACount[si] + mov dl, byte ptr DMARegSav.DMAMode[si] + inc ecx ; ECX = SIZE of transfer + test dl, DMA_M_16BIT ; Word transfer? + jz short GLexit ; N: no special treatment + + DMA_WADDR_TO_BADDR ; Y: fixup values from regs +GLexit: + ret + +DMA_GetLinAdr endp + + page +;****************************************************************************** +; DMA_SetPhyAdr - Load the Page and Base DMA registers with the input +; Physical Address and save this addr as current phy addr. +; +; ENTRY: +; EAX = physical address +; SI = DMA channel # * 16 +; DS -> DGROUP +; +; USED: Flags +;------------------------------------------------------------------------------ +DMA_SetPhyAdr proc near +; + push eax + push bx + push dx + + xor bh, bh + mov bl, [DMARegSav.DMAFF1] + cmp si,4*16 ; 2nd cntlr? + jb short DMA_SPA1 + mov bl, [DMARegSav.DMAFF2] ; yes, other flip-flop +DMA_SPA1: + test [DMARegSav.DMAMode][si], DMA_M_16BIT ; word transfer? + jz short SaveIt ; no, no translation + DMA_BADDR_TO_WADDR +SaveIt: + mov dword ptr DMARegSav.DMAPhyAdr[si], eax + + ; set page register + xor dh, dh + mov dl, byte ptr DMARegSav.DMAPagePort[si] + mov al, byte ptr DMARegSav.DMAPhyAdr.HighWord[si] + out dx, al + + ; set base address register + mov dl, byte ptr DMARegSav.DMABasePort[si] + mov al, byte ptr DMARegSav.DMAPhyAdr[si][bx] + out dx,al ; send out 1st byte + xor bl,1 ; toggle FF + jmp $+2 + jmp $+2 + mov al, byte ptr DMARegSav.DMAPhyAdr[si][bx] + out dx,al ; send out other byte + xor bl,1 ; toggle FF to original state + + pop dx + pop bx + pop eax + ret +; +DMA_SetPhyAdr endp + + page +;****************************************************************************** +; DMALoadCount - Load the Count DMA register with the input +; +; ENTRY: +; si = DMA channel # * 16 +; +;------------------------------------------------------------------------------ +DMALoadCount proc near + push bx + push ax + push dx + + xor bh, bh + mov bl, byte ptr [DMARegSav.DMAFF1] + cmp si,4*16 ;Q: Adrs from 2nd cntlr + jb short DMA_SC1 ; N: save it as is + mov bl, byte ptr [DMARegSav.DMAFF2] + +DMA_SC1: + mov dl, byte ptr DMARegSav.DMACntPort[si] + xor dh, dh + mov al, byte ptr DMARegSav.DMACount[bx][si] + out dx, al + jmp $+2 + jmp $+2 + xor bl, 1 + mov al, byte ptr DMARegSav.DMACount[bx][si] + out dx, al + + pop dx + pop ax + pop bx + ret + +DMALoadCount endp + + page +;****************************************************************************** +; DMA_DMAFixup - Fixup Linear to Physical mapping for DMA +; +; ENTRY: +; SI = 16 * channel # +; DS assume DGROUP +; +; EXIT: +; DMARegSav is updated +; +; USED: flags, registers (calls a C program, so most registers are trashed) +; +; Check to see if DMA Page fixup is needed. +; We test for the following cases for optimization: +; Lin Base Add == Lin Page Reg == 0, assume that transfer addr +; is not yet valid +; +;------------------------------------------------------------------------------ +DMA_DMAFixup proc near + ;Q: LinAddr = 0? + + mov eax, dword ptr DMARegSav.DMALinAdr[si] + or eax,eax + jz short DMA_nofixup ; Y:DMA not programmed yet + ;Do the fixup..... + pushfd ; ENABLE INTERRUPTS! + push bx ; C code trashes these regs + push es +; +; long SwapDMAPages(LinAdr, Len, XferSize); +; long LinAdr, Len; +; unsigned XferSize; 0/1 Byte/word Xfer +; + movzx eax, [DMARegSav.DMAMode][si] + and al, DMA_M_16BIT ; Non-zero for 16bit transfer + push ax ; push XferSize + + call DMA_GetLinAdr + push ecx ; push count + push eax ; push LinAdr +; +; C code saves di si bp ds ss sp + + call _SwapDMAPages ; C program to do the dirty work + + xchg ax, dx + shl eax, 16 + mov ax, dx ; eax = returned value + + add sp, 10 ; clean up stack + + pop es + pop bx + popfd ; Restore original FLAGS state + + test [DMARegSav.DMAMode][si], DMA_M_16BIT ; word transfer? + jz short SavIt ; no, no translation + DMA_BADDR_TO_WADDR ; Y: Put in special format +SavIt: + mov dword ptr DMARegSav.DMAPhyAdr[si], eax + clc ; Done fixup + ret +DMA_nofixup: + stc + ret + +DMA_DMAFixup endp + + page +;****************************************************************************** +; DMA_WrtAdrReg - Write registers associated with DMA address +; +; ENTRY: +; BX = Flip Flop State, 0 or 1 +; SI = channel # * 16 +; DS assume DGROUP +; Uses Values in DMARegSav +; +; EXIT: +; +; USED: Flags, EAX +; STACK: +;------------------------------------------------------------------------------ +DMA_WrtAdrReg proc near + +; Must Update Page and Base registers simultaneously when remapping occurs... + push bx + push dx + + and bx, 1 ; Lose extra bit just in case... + ; Base Register... + xor dh, dh ; clear high byte + + ; NOTE: Internal flip- + ; flop flag not updated, + ; since we write twice.... + ; BX = flip flop state + + mov dl, byte ptr DMARegSav.DMABasePort[si] + mov al, byte ptr DMARegSav.DMAPhyAdr[bx][si] + out dx, al ; output the byte + jmp $+2 ; timing + jmp $+2 ; timing + xor bx, 1 ; toggle flip-flop + + mov al, byte ptr DMARegSav.DMAPhyAdr[bx][si] + out dx, al ; output the byte + jmp $+2 ; timing + jmp $+2 ; timing + xor bx, 1 ; toggle flip-flop + + ; Page Register... + mov al, byte ptr DMARegSav.DMAPhyAdr.HighWord[si] ; fetch value + mov dl, byte ptr DMARegSav.DMAPagePort[si] + out dx,al ; output the byte + + pop dx + pop bx + ret + +DMA_WrtAdrReg endp + + page +;****************************************************************************** +; InitELIM - initialize LIM h/w trapping data structures and +; I/O bit map for this ports. +; +; NOTE: this is a FAR routine +; +; ENTRY: Real Mode +; +; EXIT: Real Mode +; TSS:[IOBitMap] - LIM addresses entered in I/O bit map +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +InitELIM proc far + + push ax + push bx + push cx + push si + push di + push ds + push es + + cld + + mov ax,seg DGROUP + mov ds,ax +; +; now set entries in I/O Bit Map +; + mov ax,TSS + mov es,ax ; ES -> TSS +; +; now set DMA ports in I/O Bit Map +; + mov cx,LIMDMAP_CNT + mov si,offset DGROUP:DMAP_Page ; DS:SI -> DMA ports + mov bx,8000h ; trap it every 1k +IE_maploop: + lodsw ; AX = port to trap + call PortTrap ; set bit(s) for this port + loop IE_maploop ;if more ... + + pop es + pop ds + pop di + pop si + pop cx + pop bx + pop ax + ret + +InitELIM endp + + +; +; C callable routines for manipulating page table entries. +; and Current FRS - CurRegSet + + +; +; Equates for picking up arguments passed in from C code. +; Arg1 - word Arg, +; Arg2 - word or dword Arg +; + +Arg1 equ [BP+4] +Arg2 equ [BP+6] + + +;***************************************************************************** +; +; _GetPte - called from C code +; +; return pte in dx:ax +; +; long GetPte(PTIndex) +; unsigned PTIndex; +; +; Written: JHB Aug 10,1988 +; Modif: ISP Aug 12,1988 parameter should be returned in dx:ax not eax +; removed some of pushes and pops +; added cld before load just to be safe +; offset specified in DGROUP +; +; JHB Aug 21 88 changed input param to PTIndex +; +;***************************************************************************** + +_GetPte proc near + + push bp + mov bp, sp + push si + push ds + + mov ax, PAGET_GSEL + mov ds, ax + + mov si, WORD PTR Arg1 + shl si, 2 ; dword entries in the PT + + cld + lodsw ; get low word + mov dx, ax ; into dx + lodsw ; get hiword + xchg dx, ax ; dx:ax = long return value + + pop ds + pop si + pop bp + ret +_GetPte endp + +;***************************************************************************** +; +; _SetPte - called from C code +; +; Locate the PT entry for given EmmPhyPage and set it to pte. +; +; SetPte(PTIndex, pte) +; unsigned PTIndex; +; long pte; +; +; WRITTEN: JHB Aug 10,1988 +; MODIF: ISP Aug 12,1988 pushes and pops removed +; cld added for safety +; offset specified in DGROUP +; pushed poped eax (check on this) +; +; JHB Aug 21, 1988 changed first input param to PTIndex +; +;***************************************************************************** + + +_SetPte proc near + + push bp + mov bp, sp + push di + push es + + mov ax, PAGET_GSEL + mov es, ax + mov di, WORD PTR Arg1 + shl di, 2 + + mov eax, DWORD PTR Arg2 + and ax, 0F000H ; clear low 12 bits + or ax, P_AVAIL ; page control bits - user, present, write + + cld + stosd +; +; reload CR3 to flush TLB +; + mov eax, CR3 + mov CR3, eax + +; mov eax,dword ptr [Page_Dir] ; mov EAX,dword ptr [Page_Dir] +; db 0Fh,22h,18h ; mov CR3,EAX + + pop es + pop di + pop bp + ret +_SetPte endp + +;***************************************************************************** +; +; _GetCRSEntry - called from C code +; +; return the Emm page mapped to the EmmPhyPage by looking up CurRegSet. +; +; unsigned GetCRSEntry(EmmPhyPage) +; unsigned EmmPhyPage +; +; WRITTEN: JHB Aug 10,1988 +; MODIF: ISP Aug 12,1988 pushes and pops removed +; Offset specified in DGROUP +; cld added for safety +;***************************************************************************** + +_GetCRSEntry proc near + + push bp + mov bp, sp + push di + + mov bx, WORD PTR Arg1 + shl bx, 1 ; each FRS entry is a word + Get_FRS_Window DI ; di = address of Current FRS + add di, bx + mov ax, word ptr [di] ; load FRS entry + + pop di + pop bp + ret +_GetCRSEntry endp + +; +; Equates for picking up long Arguments from C code +; LArg1 - long Arg +; Larg2 - long Arg when the first Arg is also long +; + +LArg1 equ [BP+4] +LArg2 equ [BP+8] + +;***************************************************************************** +; +; _GetDMALinAdr - called from C code +; +; returns the Lin Adr for the DMA buffer whose physical adr is given +; +; long GetDMALinAdr(DMAPhyAdr) +; long DMAPhyAdr; +; +; Get the Linear address for DMAPhyAdr. There is a pte which always +; maps to this always. MapLinear translates DMAPhyAdr to a linear adr. +; +; +; 8/12/88 JHB removed _Copy16K, changed it to this routine. +; +;***************************************************************************** + +_GetDMALinAdr proc near + + push bp + mov bp, sp + push si + push di + push ds +; +; convert the DMAPhyAdr into a linear address. +; + mov eax, dword ptr LArg1 + call MapLinear +; +; eax = 32 bit linear adr for the DMA Xfer area. +; + ror eax, 16 + mov dx, ax + ror eax, 16 ; dx:ax 32 bit linear adr to be returned + + pop ds + pop di + pop si + pop bp + ret +_GetDMALinAdr endp + +;****************************************************************************** +; +; set_selector - set up a selector address/attrib +; +; ENTRY: EAX = address for GDT selector - a linear address +; DI = GDT selector +; EXIT: selector in DI is writeable data segment,128k long and points +; to desired address. +; +;****************************************************************************** + +set_selector proc near + + push eax + push di + push es + + and di,NOT 07h ; just in case... GDT entry + push GDTD_GSEL + pop es ; ES:DI -> selector entry + + mov es:[di+2],ax ; low word of base address + + shr eax,16 ; AX = high word of address + mov es:[di+4],al ; low byte of high word of address + xor al,al ; clear limit/G bit + or al, 1 ; set LSB0 i.e. Limit16 bit for 128K Xfer + mov es:[di+6],ax ; set high byte of high word of addr + ; and high nibble of limit/G bit + ; and Limit Bit 16 for 128K transfer + mov ax,0FFFFh + mov es:[di],ax ; set limit bits 0-15 + + mov al,D_DATA0 ; writeable DATA seg / ring 0 + mov es:[di+5],al + + pop es + pop di + pop eax + + ret + +set_selector endp + +;**************************************************************************** +; _Exchange16K - called from C +; +; Exchange contents of the pages at LinAdr1 and LinAdr2 +; +; Exchange16K(LinAdr1, LinAdr2) +; long LinAdr1, LinAdr2; +; +; Written: JHB Aug 11, 1988 +; ISP Aug 12, 1988 Added cld. +; DWORD PTR mentioned explicitly +;***************************************************************************** + +_Exchange16K proc near + + push bp + mov bp, sp + push si + push di + push ds + + mov di,MBSRC_GSEL ; source selector + mov eax,dword ptr LArg1 ; load linear adr + call set_selector ; set up a selector in GDT + mov es,di + + mov di,MBTAR_GSEL ; destination selector + mov eax,dword ptr LArg2 + call set_selector ; set up selector + mov ds,di + mov cx,1000h ; 16k bytes (4 at a time) + xor di,di ; initialize index + cld +sloop: + mov eax,dword ptr es:[di] ; pick a dword at LArg1 + xchg eax,dword ptr ds:[di] ; swap with dword at LArg2 + stosd ; store new dword at LArg1 + loop sloop + + pop ds + pop di + pop si + pop bp + ret + +_Exchange16K endp + +; +; signals an exception error +; +_FatalError proc near + + push bp + mov bp, sp + + mov ax, 1 + mov bx, 3 + call ErrHndlr + + pop bp + ret + +_FatalError endp + +_TEXT ends ; end of segment + +end ; end of module + + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/EM286LL.ASM b/v4.0/src/MEMM/MEMM/EM286LL.ASM new file mode 100644 index 0000000..3b3f72e --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EM286LL.ASM @@ -0,0 +1,360 @@ + + +page 58,132 +;****************************************************************************** + title EM286LL - 386 routine to emulate 286 LOADALL +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EMM286LL - 286 loadall emulation routine +; +; Version: 0.04 +; +; Date: April 11,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/16/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/18/86 0.01 Moved EL_Off before buffer +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 06/28/86 0.02 Modified CR0 logic & Edi for LL3 buffer +; 07/03/86 0.03 Removed logic for enabling A20 watch +; 07/06/86 0.04 Change assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; +; 286 LOADALL is emulated by building a buffer for a +; 386 LOADALL from the 286 LOADALL buffer (@80:0) and executing the 386 +; LOADALL. +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public EM286ll + public ELOff +; + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include loadall.inc + include VDMseg.inc + include desc.inc + include VDMsel.inc + include instr386.inc + include vm386.inc + include oemdep.inc + +FALSE equ 0 +TRUE equ not FALSE + +; +; DescCopy +; Macro for copying a 286 Loadall descriptor cache entry to a +; 386 Loadall descriptor cache entry. +; ENTRY: DS:SI pts to 286 Loadall descriptor entry +; ES:DI pts to 386 Loadall descriptor entry +; +; EXIT: DS:SI unchanged. +; ES:DI pts to byte after 386 Loadall descriptor entry (next entry). +; *** The access rights byte in set to DPL 3 for virtual mode *** +; +; USED: EAX +; +DescCopy MACRO + XOR_EAX_EAX ; clear EAX + mov ax,word ptr [si.dc2_BASEhi] ; AL = junk, AH = Access rights + or ah,D_DPL3 ;* set DPL 3 for virtual mode access + OP32 + stosw ; store: junk->AR1,AR->AR2,0->AR3 & AR4 + OP32 + mov ax,[si] ; 24 bits of Base Addr from 286 entry + OP32 + and ax,0FFFFh ; AND EAX,00FFFFFFh + dw 000FFh ; clear high byte of base addr + call MapLinear ; Map address according to page tables + OP32 + stosw ; store Base Addr for 386 entry + XOR_EAX_EAX ; clear EAX + mov ax,[si.dc2_LIMIT] ; get low 16 bits of limit + OP32 + stosw ; store 32 bit LIMIT into 386 entry + ENDM +; +; CurCopy +; Macro for copying a current descriptor cache entry to a +; 386 Loadall descriptor cache entry. +; ENTRY: DS:BX pts to current descriptor +; ES:DI pts to 386 Loadall descriptor entry +; +; EXIT: DS:BX unchanged. +; ES:DI pts to byte after 386 Loadall descriptor entry (next entry). +; *** The access rights byte in set to DPL 3 for virtual mode *** +; +; USED: EAX +; +CurCopy MACRO + OP32 + mov ax,[bx+4] ; get AR info + or ah,D_DPL3 ;* set DPL 3 for virtual mode access + OP32 + stosw ; store into cache entry + mov ah,[bx+7] ; AX = Base[31..16] + OP32 + shl ax,16 ; high word of EAX = Base[31..16] + mov ax,[bx+2] ; EAX = Base[31..0] + OP32 + stosw + mov al,[bx+6] ; LIMIT[19..16] in low bits of AL + and ax,0Fh + OP32 + shl ax,16 ; high word of EAX = LIMIT[31..16] + ; NOTE: VDM does not use page + ; granularity for limit field !! + mov ax,[bx] ; EAX = LIMIT[31..0] + OP32 + stosw ; store into cache for 386 buffer + ENDM +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +L286BUFF segment at 80h +; +; Source 286 LoadAll buffer +; +SLBuff LoadAllBuf286 <> ; 286 loadall buffer + +L286BUFF ends + +_TEXT segment + + extrn MapLinear:near ; map linear address + extrn PortTrap:near ; IOBM trap set function (VMINIT) + +_TEXT ends + +; +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** + +_DATA segment + +ELOff dw offset ELbuff ; offset of 386 loadall buffer +ELbuff LoadAllBuf386 <> ; 386 loadall buffer + dd 0 ; filler - allow dword align + +;(0.03)extrn A20watch:byte ; Loadall/KBD A20 disable flag + +_DATA ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +_TEXT segment + ASSUME CS:_TEXT,DS:DGROUP,ES:DGROUP + +;****************************************************************************** +; EM286ll - emulate 286 Loadall +; +; ENTRY: Protected Mode +; physical address 80:0 holds 286 loadall buffer info +; +; EXIT: via Loadall to virtual mode +; The 286 Loadall buffer is emulated with the following +; exceptions: +; The VM bit is set in EFLAGS. +; The TR, IDT descriptor cache, & TSS descriptor cache are +; pointed to the VDM entries. +; +; USED: +; +;****************************************************************************** +EM286ll proc near + mov bx,GDTD_GSEL ; get GDT data alias + mov ds,bx ; DS -> GDT + mov bx,800h ; BX = VM CS (segment form) + mov ds:[VM1_GSEL+2],bx ; place in descriptor + xor bx,bx + mov ds:[VM1_GSEL+4],bh ; place in descriptor + mov bx,VM1_GSEL + mov ds,bx ; DS:0 points to 286 loadall buffer + ASSUME DS:L286BUFF +; + mov ax,VDMD_GSEL + mov es,ax + mov di,ES:[ELOff] ; ES:DI pts to 386 loadall buffer +; + cld +; + MOV_EAX_CR0 ; mov EAX,CR0 + and ax,0FFF1h ;clear current TS,EM, & MP bits + mov cx,[SLBuff.ll2_MSW] ; CX = 286 ll_buff MSW + and cx,000Eh ;retain 286 TS,EM, & MP bits + or ax,cx ; set client's TS,EM, & MP bits + OP32 + stosw ; store CR0 for 386 buffer +; + OP32 + mov ax,0000h + dw 0002h ; VM bit on + mov ax,[SLBuff.ll2_FLAGS] ; get low word of flags + or ax,3000h ; set IOPL to 3 + OP32 + stosw ; store EFLAGS for 386 buffer +; + XOR_EAX_EAX ; clear EAX + mov ax,[SLBuff.ll2_IP] ; get 286 IP - high word of EAX clear + OP32 + stosw ; store EIP for 386 buffer +; +; Copy the client's EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX +; register images from his 386 loadall buffer to our 386 loadall buffer +; + mov si,offset ll2_DI ; DS:SI pts to DI in 286 buffer + mov cx,8 +CopyGen: ; Copy General Purpose Registers + lodsw ; EAX = reg image from client's buffer + OP32 + stosw ; store it in our 386 buffer + loop CopyGen + +; +; 386 debug registers +; + MOV_EAX_DR6 + OP32 + stosw ; store DR6 in our 386 buffer + + MOV_EAX_DR7 + OP32 + stosw ; store DR7 in our 386 buffer +; + XOR_EAX_EAX ; clear EAX +; + mov ax,TSS_GSEL ; get current TR for VDM's TSS !!! + OP32 + stosw ; store TR for 386 buffer +; + mov si,offset ll2_LDT ; DS:SI pts to LDT in 286 buffer + lodsw ; get LDT entry from 286 buffer + OP32 + stosw ; store LDT for 386 buffer + + OP32 + stosw ; store junk into GS for 386 buffer + + OP32 + stosw ; store junk into FS for 386 buffer + +; +; Copy the client's DS, SS, CS, ES register images from his 286 loadall +; buffer to our 386 loadall buffer +; + mov cx,4 +CopySeg: ; Copy Segment Registers + lodsw ; get seg image from client's buffer + OP32 + stosw ; store it in our 386 buffer + loop CopySeg + + ; ES:DI pts to 386 TSS cache entry +; +; Copy the current TSS, IDT, & GDT descriptors from the GDT table to +; our 386 loadall buffer +; + push ds ; save client's buffer selector + mov ax,GDTD_GSEL + mov ds,ax + + mov cx, 3 + mov bx, TSS_GSEL + push word ptr GDTD_GSEL + push word ptr IDTD_GSEL + +CopyCur: ; Copy current descriptors + CurCopy ; DS:[BX] points to current descriptor + pop bx + loop CopyCur + mov ds, bx ; restore client's buffer selector + +; + ; ES:DI pts to 386 LDT cache entry + mov si,offset ll2_LDTcache ; DS:SI pts to 286 LDT cache entry + DescCopy ; store LDT cache for 386 buffer +; + XOR_EAX_EAX ; clear EAX- use 0 for GS/FS caches + + OP32 + stosw ; store GS cache for 386 buffer + OP32 + stosw + OP32 + stosw +; + OP32 + stosw ; store FS cache for 386 buffer + OP32 + stosw + OP32 + stosw +; +; Copy the client's DS, SS, CS, ES register cache images from +; his 286 loadall buffer to our 386 loadall buffer +; + mov si,offset ll2_DScache ; DS:SI pts to 286 DS cache entry + mov cx,4 +CopyCac: ; ES:DI pts to our 386 ll cache entry + DescCopy ; store his cache in our 386 buffer + sub si,06h ; DS:SI pts to client's cache entry + loop CopyCac +; +; 386 Loadall buffer complete +; + +;(0.03) push es +;(0.03) mov ax, TSSD_GSEL ; Point ES to TSS for PortTrap +;(0.03) mov es, ax +;(0.03) mov bh, 80h ; set every 1k +;(0.03) mov ax, KbdDataPort +;(0.03) call PortTrap ; set traps on keyboard ports +;(0.03) mov ax, KbdCmdPort ; in case client +;(0.03) call PortTrap ; tries to disable A20 +;(0.03) pop es +;(0.03) mov es:[A20watch], YesLLdone ; set A20 watch flag + + HwTabLock ; Hardware lock the high ram + + OP32 + xor di,di ; clear EDI + mov di,ES:[ELOff] ; ES:EDI pts to loadall buffer + dw LODAL386 ; execute 386 LOADALL + + ASSUME DS:DGROUP +; +EM286ll endp + +_TEXT ends + end diff --git a/v4.0/src/MEMM/MEMM/EM386LL.ASM b/v4.0/src/MEMM/MEMM/EM386LL.ASM new file mode 100644 index 0000000..3408eaa --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EM386LL.ASM @@ -0,0 +1,397 @@ + + +page 58,132 +;****************************************************************************** + title EM386LL - 386 routine to emulate 386 LOADALL +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EM386LL - 386 routine to emulate 386 LOADALL +; +; Version: 0.04 +; +; Date: April 11,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/16/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 06/29/86 0.02 Fixed error handler call. Error handler called +; only on attempt to set VM bit in EFLAGS +; 06/30/86 0.02 Jmp to error routine (instead of calling) +; 07/03/86 0.03 Removed logic to enable A20 line watch +; 07/05/86 0.04 JumpReal in R_CODE +; 07/06/86 0.04 Changed assume to DGROUP +; 07/08/86 0.04 added DB67 NOPs to avoid B1 errata +; +;****************************************************************************** +; +; Functional Description: +; +; 386 LOADALL is emulated by building a buffer for a +; 386 LOADALL from the client's 386 LOADALL buffer and executing the 386 +; LOADALL. +; +; check DR6/DR7 for addresses > 1meg ? +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public EM386ll +; + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include loadall.inc + include VDMseg.inc + include desc.inc + include VDMsel.inc + include instr386.inc + include vm386.inc + include oemdep.inc + +FALSE equ 0 +TRUE equ not FALSE + +; +; Desc3Copy +; Macro for copying a 386 Loadall descriptor cache entry to a +; 386 Loadall descriptor cache entry. +; ENTRY: DS:ESI pts to client's 386 Loadall descriptor entry +; ES:DI pts to our 386 Loadall descriptor entry +; +; EXIT: DS:ESI pts to byte after client's 386 ll descr entry (next entry). +; ES:DI pts to byte after 386 Loadall descriptor entry (next entry). +; *** The access rights byte in set to DPL 3 for virtual mode *** +; +; USED: EAX +; +Desc3Copy MACRO + OP32 + EA32 ; EAX = dword from DS:[ESI] + lodsw ; get access rights + + or ah,D_DPL3 ;* set DPL 3 for virtual mode access + + OP32 + stosw ; store access rights + + OP32 + EA32 ; EAX = dword from DS:[ESI] + lodsw ; 32 bits of Base Addr from 386 entry + + call MapLinear ; map this linear addr by page tables + + OP32 + stosw ; store Base Addr for 386 entry + + OP32 + EA32 ; EAX = dword from DS:[ESI] + lodsw ; get 32 bits of limit + + OP32 + stosw ; store 32 bit LIMIT into 386 entry + ENDM + +; +; CurCopy +; Macro for copying a current descriptor cache entry to a +; 386 Loadall descriptor cache entry. +; ENTRY: DS:BX pts to current descriptor +; ES:DI pts to 386 Loadall descriptor entry +; +; EXIT: DS:BX unchanged. +; ES:DI pts to byte after 386 Loadall descriptor entry (next entry). +; *** The access rights byte in set to DPL 3 for virtual mode *** +; +; USED: EAX +; +CurCopy MACRO + OP32 + mov ax,[bx+4] ; get AR info + or ah,D_DPL3 ;* set DPL 3 for virtual mode access + OP32 + stosw ; store into cache entry + mov ah,[bx+7] ; AX = Base[31..16] + OP32 + shl ax,16 ; high word of EAX = Base[31..16] + mov ax,[bx+2] ; EAX = Base[31..0] + OP32 + stosw + mov al,[bx+6] ; LIMIT[19..16] in low bits of AL + and ax,0Fh + OP32 + shl ax,16 ; high word of EAX = LIMIT[31..16] + ; NOTE: VDM does not use page + ; granularity for limit field !! + mov ax,[bx] ; EAX = LIMIT[31..0] + OP32 + stosw ; store into cache for 386 buffer + ENDM + +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** + +_DATA segment +extrn ELOff:word ; offset of 386 loadall buffer +_DATA ends + + +R_CODE segment +extrn JumpReal:far ; continue client in real mode (rrtrap.asm) +R_CODE ends + +_TEXT segment +extrn MapLinear:near ; maps linear addresses (maplin.asm) +extrn PortTrap:near ; IOBM trap set function (vminit.asm) +extrn ErrHndlr:near ; error handler (errhndlr.asm) +_TEXT ends + + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +_TEXT segment + ASSUME CS:_TEXT,DS:DGROUP,ES:DGROUP + +;****************************************************************************** +; EM386ll - emulate 386 Loadall +; The basic approach here is to filter the client's loadall buffer into +; a temporary buffer, setting our values for the parameters we don't want +; him to change and then executing the 386 loadall from our buffer. +; +; ENTRY: Protected Mode +; BP points to bottom of client's GPfault stack frame +; ES(in GP frame):EDI points to the client's loadall buffer info +; on stack: ESI,EBX,EBP +; +; EXIT: via Loadall to virtual mode +; The 386 Loadall buffer is emulated with the following +; exceptions: +; The VM bit is set in EFLAGS. +; The TR, IDT descriptor cache, & TSS descriptor cache are +; pointed to the VDM entries. +; +; USED: Not applicable... loadall reloads all registers +; +;****************************************************************************** +EM386ll proc near +; + PUSH_EAX + PUSH_ECX + PUSH_EDI + +; Build a descriptor to client's 386 loadall buffer + + mov bx,GDTD_GSEL ; get GDT data alias + mov ds,bx ; DS -> GDT + mov bx, [bp.VTFOE+VMTF_ES] ; Get VM ES from GP stack frame + mov ax,bx + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + shr ax, 4 ; AH = high 8 bits of base + mov ds:[VM1_GSEL+4],ah ; place in descriptor + +; Point DS:ESI to start of client's 386 loadall buffer + mov bx,VM1_GSEL + mov ds,bx + OP32 + mov si,di + ASSUME ds:nothing + +; Point ES:EDI to start of our 386 loadall buffer + + mov ax,VDMD_GSEL + mov es,ax + OP32 + xor di,di ; clear EDI + mov di,ES:[ELOff] ; ES:EDI pts to our 386 loadall buffer +; + cld + +; Walk through the two buffers in parallel, copying the client's values +; when appropriate + +; +; CR0 entry +; + EA32 + OP32 + lodsw ; get client's CR0 + +;(0.02) OP32 +;(0.02) test ax,0001h ; TEST EAX,80000001h +;(0.02) dw 8000h ; Q: PG or PE bit set ? +;(0.02) jz CR0_OK ; N: continue +;(0.02) call Em386_Err ; Y: error +; +CR0_OK: + MOV_ECX_CR0 + OP32 + and cx,0011h ; and ECX,80000011h + dw 8000h ; save only PG,ET, & PE bits + OP32 + or ax,cx ; or EAX,ECX + OP32 + stosw ; store CR0 for 386 buffer + XOR_ECX_ECX ; clear ECX +; +; EFLAGS +; + EA32 + OP32 + lodsw ; get EFLAGS +; + OP32 + test ax,0000h + dw 0002h ;Q: client's VM bit set ? + jz EF_OK ; N: continue + jmp Em386_Err ; Y: error handler - won't return here +EF_OK: + and ax,0FFFh ; clear IOPL & NT bits + OP32 + or ax,3000h + dw 0002h ; set VM bit and IOPL = 3 + OP32 + stosw ; store EFLAGS for 386 buffer +; +; Copy the client's EIP, EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX, DR6 & DR7 +; register images from his 386 loadall buffer to our 386 loadall buffer +; + mov cx,11 ; copy 11 register contents + OP32 ; dwords from DS:[ESI] to ES:[EDI] + EA32 + rep movsw ; copy 11 dwords + + EA32 + nop ; this avoids a B1 errata +; +; store TR and LDTR +; + XOR_EAX_EAX ; clear EAX + mov ax,TSS_GSEL ; get current TR for VDM's TSS !!! + OP32 + stosw ; store TR for 386 buffer +; + sldt ax ; use current LDT + OP32 + stosw ; store LDTR for 386 buffer +; +; Copy the client's GS, FS, DS, SS, CS, ES register images from +; his 386 loadall buffer to our 386 loadall buffer +; + add si,offset ll3_GS - offset ll3_TSSR + mov cx,6 + OP32 ; dwords from DS:[ESI] to ES:[EDI] + EA32 + rep movsw ; copy 6 dwords + + EA32 + nop ; this avoids a B1 errata +; +; Copy the current TSS, GDT, IDT, LDT descriptors from the GDT table to +; our 386 loadall buffer +; + push ds ; save client's buffer selector + mov ax,GDTD_GSEL + mov ds,ax + + mov cx, 4 + mov bx, TSS_GSEL + push word ptr LDTD_GSEL + push word ptr GDTD_GSEL + push word ptr IDTD_GSEL + +CopyCur: ; Copy current descriptors + CurCopy ; DS:[BX] points to current descriptor + pop bx + loop CopyCur + mov ds, bx ; restore client's buffer selector + + ; DS:SI pts to 386 GS cache entry +; +; Copy the client's GS, FS, DS, SS, CS, ES register cache images from +; his 386 loadall buffer to our 386 loadall buffer +; + add si,offset ll3_GScache - offset ll3_TSScache + mov cx,6 +CopyCac: ; ES:DI pts to our 386 buf cache entry + Desc3Copy ; store his cache in our 386 buffer + loop CopyCac ; DS:SI pts to client's buf cache entry + +; +; 386 Loadall buffer complete +; + +;(0.03) push es +;(0.03) mov ax, TSSD_GSEL ; Point ES to TSS for PortTrap +;(0.03) mov es, ax +;(0.03) mov bh, 80h ; set every 1k +;(0.03) mov ax, KbdDataPort +;(0.03) call PortTrap ; set traps on keyboard ports +;(0.03) mov ax, KbdCmdPort ; in case client +;(0.03) call PortTrap ; tries to disable A20 +;(0.03) pop es +;(0.03) mov es:[A20watch], YesLLdone ; set A20 watch flag + + HwTabLock ; Hardware lock the high ram + + OP32 + xor di,di ; XOR EDI,EDI - clear EDI + mov di,ES:[ELOff] ; ES:EDI pts to loadall buffer + dw LODAL386 ; execute 386 LOADALL + + ASSUME DS:DGROUP +; +; +EM386ll endp + + page +;****************************************************************************** +; Em386_Err - handle 386 ll emulation error +; This routine is currently called only on attempts to set the +; VM bit via loadall. +;****************************************************************************** +Em386_Err proc near + push ax + push bx + mov ax, PrivErr + mov bx, Err3LL + call ErrHndlr + pop bx + pop bx +; +; continue client in real mode +; + POP_EDI ; restore used regs + POP_ECX + POP_EAX + ; stack back to VmFault exit condition + + jmp JumpReal ; "jump" to real mode and continue interrupted + ; code. + +Em386_Err endp +; +_TEXT ends + end diff --git a/v4.0/src/MEMM/MEMM/EMM.ASM b/v4.0/src/MEMM/MEMM/EMM.ASM new file mode 100644 index 0000000..557afa4 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMM.ASM @@ -0,0 +1,522 @@ + + + page 58,132 +;****************************************************************************** + title EMM - Expanded Memory Manager interface for MEMM +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EMM - Expanded Memory Manager interface +; +; Version: 0.05 +; +; Date: June 14, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 06/14/86 original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 06/29/86 0.02 Protect port 84/85 from ints +; 07/05/86 0.04 moved EMM_rEntry to R_CODE +; 07/06/86 0.04 Changed assume to DGROUP +; 07/08/86 0.04 Changed EMM_pEntry to call EMM functions +; directly +; 07/10/86 0.05 jmp $+2 before "POPF" +; 07/10/86 0.05 added EMM_Flag +; 06/09/88 remove _map_known since there is no map now (pc) +; 07/20/88 remove debugger code (pc) +; +;****************************************************************************** +; Functional Description: +; The module contains code for calling the EMM functions and a routine +; for managing the AUTO mode of MEMM. +; There are two EMM entry points in this module; one for real/virtual +; mode entry and one for protected mode (IDT entry points here). When +; MEMM is ON (system in Virtual mode), INT 67H calls transition to protected +; mode and the EMM_pEntry entry point. EMM_pEntry sets up the same stack +; conditions as the generic int67_Entry dispatcher and calls the appropriate +; EMM function. Some EMM functions cannot be executed in protected mode. +; These functions are called by reflecting the INT 67H to the real/virtual +; mode entry point. EMM functions which are executed in PROTECTED mode +; will take less time (they don't suffer the extra time to reflect the +; INT 67H). +; +;****************************************************************************** +.lfcond +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public EMM_pEntry ; protected mode entry point + public EMM_rEntry ; real mode entry point + public EMM_rEfix ; label for far jump to int67_entry + public _AutoUpdate ; update auto mode of VDM/EMM + public EMM_Flag ; flag for EMM calls + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include vdmseg.inc + include vdmsel.inc + include vm386.inc +; include instr386.inc + include oemdep.inc + include emmdef.inc + +FALSE equ 0 +TRUE equ not FALSE + +; +; these EMM functions are handled in protected mode +; +EMM_MAP_PAGE equ 44h ; map handle page +EMM_RESTORE equ 48h ; restore page map +EMM_GET_SET equ 4Eh ; get/set page map +EMM_GET_SET_PARTIAL equ 4Fh ; get/set partial page map +EMM_MAP_PAGE_ARRAY equ 50h ; map handle page array +EMM_ALTER_MAP_JUMP equ 55h ; alter mapping and jump +EMM_ALTER_MAP_CALL equ 56h ; alter mapping and call +EMM_MOVE_XCHG_MEM equ 57h ; move/xchg memory region +EMM_ALTER_MAP_REG_SET equ 5Bh ; alternate map register set + +EMM_HW_MALFUNCTION equ 81h ; + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +ABS0 segment use16 at 0000h + + org 67h * 4 ; EMM function interrupt +EMMVec dw ? ; offset of vector + dw ? ; segment of vector + +ABS0 ends + +_DATA segment + +extrn _EMMstatus:word +extrn Active_Status:byte ; current VDM status +extrn Auto_Mode:byte ; current Auto mode status +;extrn _map_known:byte ; non-zero => I/O map known to a user +extrn _handle_count:word ; number of active EMM handles +extrn _regp:word ; pointer to args on stack + +_DATA ends + +_TEXT segment + +extrn int67_Entry:far ; it's far because we need CS on stack too +extrn GoVirtual:near +extrn ErrHndlr:near +extrn hw_int:near +extrn RRProc:near + +extrn _GetStatus:near +extrn _GetPageFrameAddress:near +extrn _GetUnallocatedPageCount:near +extrn _AllocatePages:near +extrn _MapHandlePage:near +extrn _DeallocatePages:near +extrn _GetEMMVersion:near +extrn _SavePageMap:near +extrn _RestorePageMap:near +extrn _GetPageMappingRegisterIOArray:near +extrn _GetLogicalToPhysicalPageTrans:near +extrn _GetEMMHandleCount:near +extrn _GetEMMHandlePages:near +extrn _GetAllEMMHandlePages:near +extrn _GetSetPageMap:near + +extrn _GetSetPartial:near +extrn _MapHandleArray:near +extrn _AlterMapAndJump:near +extrn _AlterMapAndCall:near +extrn _MoveExchangeMemory:near +extrn _AlternateMapRegisterSet:near + +_TEXT ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +_DATA segment +EMM_Flag db 0 ; non-zero => EMM function called by our code +_DATA ends + + page +;****************************************************************************** +; +; _TEXT Code Segment +; +;****************************************************************************** +; +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP +;****************************************************************************** +; protected mode dispatch table +; allocate(43h)/deallocate(45h) pages and get I/O map (49h) +; MUST be reflected to Virtual mode +; MapHandlePage,RestorePageMap,GetSetPageMap,GetSetPartial, +; MapHandleArray,MoveExchangeMemory,AlterMapAndJump, +; AlterMapAndCall and AlternateMapRegisterSet are protected mode ONLY. +;****************************************************************************** +EpE_Dispatch label word + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:_MapHandlePage ;44h + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:_RestorePageMap ;48h + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:_GetSetPageMap ;4eh + dw offset _TEXT:_GetSetPartial ;4fh + dw offset _TEXT:_MapHandleArray ;50h + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:_AlterMapAndJump ;55h + dw offset _TEXT:_AlterMapAndCall ;56h + dw offset _TEXT:_MoveExchangeMemory ;57h + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + dw offset _TEXT:_AlternateMapRegisterSet ;5bh + dw offset _TEXT:EpE_Null + dw offset _TEXT:EpE_Null + + page +;****************************************************************************** +; EMM_pEntry - protected mode entry point for EMM function calls +; +; ENTRY: Protected mode +; DGROUP:[EMM_Flag] = zero => reflect this int +; SS:[SP] pointing to virtual mode INT stack frame +; +; EXIT: Protected mode +; if this EMM function is to be handled in protected mode, +; registers as set by EMM functions +; else +; reflect int 67 to virtual mode EMM code +; +; NOTE: ***** +; Allocate(43h)/deallocate(44h) pages and get I/O map (49h) +; MUST be reflected to Virtual mode. +; +; USED: none +; +;****************************************************************************** +; +; reflect EMM function to real mode +; +EpE_reflect: + push 67h ; refect + jmp hw_int ; it... +; +; +; client not in Virtual mode +; +EpE_not_VM: + pop ebp ; N: call error handler + + mov ax,ExcpErr ; exception error + mov bx,ErrINTProt ; invalid software interrupt + call ErrHndlr +; +; function entry +; +EMM_pEntry proc near +; + push ebp + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ;Q:client in Virtual mode ? + jz EpE_not_VM ; N: handle it + ; Y: check flag + push VDMD_GSEL + pop ds ; DS = DGROUP + push VDMD_GSEL + pop es ; ES = DGROUP + cmp [EMM_Flag],0 ;Q: did we do this int67 ? + je EpE_Reflect ; N: reflect it + mov [EMM_Flag],0 ; Y: clear EMM_Flag for next + ; time and handle function + ; in protected mode. +; +; dispatch EMM function OR reflect to real/vm dispatcher +; +EpE_chk_func: + HwTabUnlock ; unlock ROM + + push [bp.VTFO+VMTF_FS] ; client FS + push [bp.VTFO+VMTF_GS] ; client GS + push [bp.VTFO+VMTF_ES] ; client ES + push [bp.VTFO+VMTF_DS] ; client DS + push [bp.VTFO+VMTF_EFLAGS] ; client Flag + push [bp.VTFO+VMTF_CS] ; client CS + push word ptr [bp.VTFO+VMTF_EIP] ; client IP (low word of EIP) + ; stack has - IP,CS,PFlag,DS,ES,GS,FS + pushad ; all regs saved + mov bp,sp ; SS:BP -> to stack args (see r67_Frame struc) + mov [_regp],sp ; regp points to regs on stack + mov [_regp+2],ss ; regp now has a far ptr to regs + + push ax + mov ax, PFLAG_VIRTUAL ; Faked VM bit + or [bp.PFlag], ax ; Incorpated in PFlag + pop ax + ; + ; validate function code + ; + sub ah,40h ; check if entry code too small + jb EpE_inv_exit ; if so, error exit + cmp ah,(5Dh-40h) ; check if entry code too big + ja EpE_inv_exit ; if so, error exit + ; else, AH = 0 base function # + ; + ; call through the jump table + ; +EpE_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:EpE_Dispatch[si] ; call function + + ; + ; check to see if we need to patch CS:IP on the iretd stack frame + ; +EpE_Exit: + test word ptr [bp.PFlag], PFLAG_PATCH_CS_IP + jz EpE_No_Patch + + mov bp, sp ; use bp to address stack + ; + ; patch iretd's CS:EIP to new CS:IP on stack + ; + mov ax, [bp.retaddr] ; get return IP + mov [bp.rFS+6], ax ; iretd's IP (6 bytes beyond FS) + xor ax, ax + mov [bp.rFS+8], ax ; zero high word of EIP + mov ax, [bp.rCS] ; get return CS + mov [bp.rFS+10], ax ; iretd's CS + +EpE_No_Patch: + popad ; restore regs + add sp, 6 ; throw away return addr cs and ip and flags + pop [bp.VTFO+VMTF_DS] ; client DS + pop [bp.VTFO+VMTF_ES] ; client ES + pop [bp.VTFO+VMTF_GS] ; client GS + pop [bp.VTFO+VMTF_FS] ; client FS + + + pop ebp ; restore bp + + HwTabLock ; lock ROM + + iretd ; return to virtual mode caller +; +; Null function - do nothing (should not get to here) +EpE_Null: + ret ; return after doing nothing +; +; EMM error handling +; +EpE_inv_exit: ; set invalid function code error + mov byte ptr [bp.rAX+1],INVALID_FUNCTION + jmp EpE_Exit + +EMM_pEntry endp + + page +;****************************************************************************** +; EMM_rLink - real/virtual mode link for EMM function calls from +; R_CODE segment. +; +; ENTRY: real/virtual mode +; all registers as set by user +; +; EXIT: real/virtual mode +; registers as set by EMM functions +; +; USED: none +; +;****************************************************************************** +EMM_rLINK proc far + + ; + ; check for protected mode ONLY function + ; + cmp ah,EMM_MAP_PAGE ;Q: map handle page function ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_RESTORE ;Q: restore page map function ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_GET_SET ;Q: get/set page map function ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_GET_SET_PARTIAL ;Q: get/set partial function ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_MAP_PAGE_ARRAY ;Q: map handle page array ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_ALTER_MAP_JUMP ;Q: alter map and jump ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_ALTER_MAP_CALL ;Q: alter map and call ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_MOVE_XCHG_MEM ;Q: move/xchg memory region ? + je ErE_GoProt ; Y: do it in protected mode + cmp ah,EMM_ALTER_MAP_REG_SET;Q: alternate map register set ? + je ErE_GoProt ; Y: do it in protected mode + ; N: do it in real/virtual mode + ; + ; here for real/virtual mode functions + ; + push fs + push gs + push es + push ds + push 00 ; PFlag => real mode call to EMM functions + push seg DGROUP + pop ds ; set DS = DGROUP + call int67_Entry ; call dispatcher + add sp,2 ; drop PFlag arg + pop ds ; restore seg regs + pop es + pop gs + pop fs + ret ; and return + + ; + ; Here if protected mode function called via real IDT + ; - set EMM flag and go for it... + ; +ErE_GoProt: + push ds + push seg DGROUP + pop ds ; DS = DGROUP + cmp [Active_Status],0 ;Q: are we in Virtual Mode ? + jne ErE_Pcall ; Y: call protected mode function +; mov [_map_known],TRUE ; N: set global auto mode flag + call _AutoUpdate ; go into virtual mode + ; and call function +ErE_Pcall: + mov [EMM_Flag],TRUE ; set flag + pop ds ; restore DS + int 67h ; go for it ... + ret ; then return + +EMM_rLINK endp + + page +;****************************************************************************** +; _AutoUpdate - updates the EMM status when in AutoMode +; +; ENTRY: REAL or VIRTUAL mode ONLY +; DS = DGROUP segment +; DS:[Auto_Mode] = non-zero => system currently in auto mode +; DS:[Active_Status] = non-zero => system currently ON +; DS:[_map_known] = non-zero => I/O map has been given to a user +; +; EXIT: exits in real or virtual depending on the state variables +; DS:[Active_Status] = current ON/OFF status +; +; USED: none +; +;****************************************************************************** +_AutoUpdate proc near +; + cmp [Auto_Mode],0 ;Q: in Auto mode now ? + je AU_exit ; N: exit + cmp [Active_Status],0 ; Y:Q: ON now ? + je AU_chkoff ; N: check OFF state status +; +; here if we are currently ON +; +; cmp [_map_known],0 ; Y:Q: map known ? +; jne AU_exit ; Y: then stay ON... + cmp [_handle_count],0 ; N:Q: any active handles ? + jne AU_exit ; Y: then stay ON... + mov [Active_Status],0 ; N: go to OFF state + push ax + call RRProc ; Force processor into real mode + pop ax + jmp AU_exit ; and leave in real mode +; +; here if we are currently OFF +; +AU_chkoff: + cmp [_handle_count],0 ;Q: any active handles ? + je AU_exit ; N: stay off + +; cmp [_map_known],0 ;; Q: is the map known ? +; je AU_exit ;; N: then stay OFF... + +AU_ON: ; Y: turn ON EMM + mov [Active_Status],1 ; go to ON state, + call GoVirtual ; and go to virtual mode (ON) +AU_exit: + ret +; +_AutoUpdate endp + +_TEXT ends + + page +;****************************************************************************** +; +; R_CODE Code Segment +; +;****************************************************************************** +; +R_CODE segment + assume cs:R_CODE, ds:DGROUP, es:DGROUP + + page +;****************************************************************************** +; EMM_rEntry - real/virtual mode entry point for EMM function calls +; +; ENTRY: real/virtual mode +; all registers as set by user +; +; EXIT: real/virtual mode +; registers as set by EMM functions +; +; USED: none +; +;****************************************************************************** +EMM_rEntry proc near +; + cli ; just in case pushf/call far + +EMM_rEfix: + call EMM_rLink ; call _TEXT segment link + iret ; return to caller +; +EMM_rEntry endp + + +R_CODE ends + + end + diff --git a/v4.0/src/MEMM/MEMM/EMM386.INC b/v4.0/src/MEMM/MEMM/EMM386.INC new file mode 100644 index 0000000..2b1143c --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMM386.INC @@ -0,0 +1,49 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: EMM386.INC - general includes for MEMM +; +; Version: 0.02 +; +; Date: May 25,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 04/25/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +; +; Message Flag Equates +; +INC_PRC_MSG equ 00000001b ; Incorrect processor type message +INC_DOS_MSG equ 00000010b ; Incorrect DOS message +MEM_ERR_MSG equ 00000100b ; Memory error message +INS_ERR_MSG equ 00001000b ; Already Installed message +NO_PF_MSG equ 00010000b ; Nowhere to put PF message +SIZE_ADJ_MSG equ 00100000b ; EMM Pool size adjusted message +BASE_ADJ_MSG equ 01000000b ; Page Frame Base adjusted msg +MAPA_ADJ_MSG equ 10000000b ; Map register address adjusted msg +INV_PARM_MSG equ 100000000b ; Invalid parameter message +PF_WARN_MSG equ 1000000000b ; PF located over ROM warning message +; +; These messages cause MEMM to not install +; +KILLER_MSG = INC_PRC_MSG+INC_DOS_MSG+MEM_ERR_MSG+INS_ERR_MSG+NO_PF_MSG +; +.list ; end of EMM386.INC diff --git a/v4.0/src/MEMM/MEMM/EMM386.LNK b/v4.0/src/MEMM/MEMM/EMM386.LNK new file mode 100644 index 0000000..f48b430 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMM386.LNK @@ -0,0 +1,41 @@ +memm386+ +elimfunc+ +emm+ +emmmes+ +emminit+ +memmonf+ +init+ +m_state+ +rom_srch+ +ppage+ +allocmem+ +inittab+ +shiphi+ +extpool+ +vdminit+ +i286+ +i386+ +tabdef+ +trapdef+ +vmtrap+ +vminst+ +elimtrap+ +iotrap+ +a20trap+ +oemproc+ +initepg+ +vminit+ +em286ll+ +em386ll+ +moveb+ +maplin+ +retreal+ +rrtrap+ +errhndlr+ +ekbd+ +util+ +initdeb+ +mapdma +emm386.exe +emm386.map/m +..\emm\emmlib.lib diff --git a/v4.0/src/MEMM/MEMM/EMM386D.LNK b/v4.0/src/MEMM/MEMM/EMM386D.LNK new file mode 100644 index 0000000..fd07081 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMM386D.LNK @@ -0,0 +1,41 @@ +memm386+ +elimfunc+ +emmD+ +emmmes+ +emminit+ +memmonf+ +init+ +rom_srch+ +ppage+ +allocmem+ +inittab+ +vdminitD+ +i286+ +i386+ +tabdefD+ +trapdef+ +kbd+ +print+ +vmtrapD+ +vminstD+ +elimtrap+ +iotrap+ +a20trap+ +oemproc+ +initepg+ +vminit+ +em286ll+ +em386ll+ +moveb+ +maplin+ +retreal+ +rrtrap+ +errhndlr+ +ekbd+ +util+ +initdebD+ +mapdma +emm386d.exe +emm386d.map/m +..\deb386\buglib.lib ..\emm\emmlib.lib + diff --git a/v4.0/src/MEMM/MEMM/EMMCOM.LNK b/v4.0/src/MEMM/MEMM/EMMCOM.LNK new file mode 100644 index 0000000..a1b6a4d --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMMCOM.LNK @@ -0,0 +1,5 @@ +memmcom+ +memmonf +emmcom.exe +emmcom.map/m; + diff --git a/v4.0/src/MEMM/MEMM/EMMINIT.ASM b/v4.0/src/MEMM/MEMM/EMMINIT.ASM new file mode 100644 index 0000000..65527b9 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMMINIT.ASM @@ -0,0 +1,678 @@ + + + page 58,132 +;****************************************************************************** + title EMMINIT - Expanded Memory Manager initialization +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EMMINIT - Expanded Memory Manager initialization routine +; +; Version: 0.05 +; +; Date: May 24 ,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 04/16/86 Original Adapted from DOS clock driver. +; 05/24/86 0.00 From EMML test driver. +; 06/21/86 0.02 added cld to EMM_Init +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 06/29/86 0.02 INC AX (was INC AL) for emm_free init +; 07/06/86 0.04 Size _emm_page,_emm_free, & _pft386 based +; on # of pages in system +; 07/06/86 0.04 Changed assume to DGROUP +; 07/10/86 0.05 moved int 67h patch to INIT +; 06/07/88 added FRS_array initialization (Paul Chan) +; +;****************************************************************************** +; Functional Description: +; This module initializes the data structures for the EMM +; and sets the current emm data break address (_emm_brk). +; +;****************************************************************************** +.lfcond +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public EMM_Init + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include vdmseg.inc + include emmdef.inc + +FALSE equ 0 +TRUE equ not FALSE + +EMM_HW_ERROR equ 81h ; EMM h/w error status + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +_DATA segment + +extrn pool_size:word ; size of EMM Pages Pool in kbytes +extrn xbase_addr_h:byte ; bit 16-24 of address of first byte of emm memory +extrn xbase_addr_l:word ; bit 0-15 of address of first byte of emm memory +extrn sys_size:word ; number of 16k pages taken away from conv. mem +extrn PageT_Seg:word ; segment of system page table + +extrn _PF_Base:word ; segment addr of page frame base +extrn _page_frame_pages:word ; number of pages in 3.2 page frame + +extrn _EMMstatus:word ; status of EMM + +extrn _page_frame_base:word ; pointers into page tables for each window +extrn _mappable_pages:word ; mappable page array +extrn _EMM_MPindex:byte ; index into mappable page array +extrn _physical_page_count:word ; number of physical pages +extrn _mappable_page_count:word ; number of mappable pages + +extrn _cntxt_pages:word ; pages in a context +extrn _cntxt_bytes:word ; bytes in a context + +extrn _emm_page:word ; ptr to array of EMM pages +extrn _free_count:word ; # of free EMM pages +extrn _emmpt_start:word ; start of empty part of emm page +extrn _emm_free:word ; ptr to array of free EMM pages +extrn _free_top:word ; top of _emm_free + +extrn _total_pages:word ; total # of EMM pages available +extrn _pft386:word ; ptr to array of page table entries + +extrn _emm_brk:word ; offset for emm data break address + +extrn FRS_array:word ; +extrn CurRegSetn:byte +extrn CurRegSet:word +extrn FRS_free:byte + +extrn _handle_table:word +extrn _handle_count:word + +_DATA ends + +ifndef NOHIMEM +else +VDATA segment +extrn vdata_begin:byte +VDATA ends +endif + +LAST segment +extrn mappable_segs:byte +LAST ends + +_TEXT segment +extrn InitELIM:far +_TEXT ends + +LAST segment +extrn InitEPage:near +LAST ends + + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +;****************************************************************************** +; +; Code Segment +; +;****************************************************************************** +;****************************************************************************** +; MACROS used in the EMM initialisation code +;****************************************************************************** +;****************************************************************************** +; +; 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 + +;****************************************************************************** +;**init_PAGE_FRAME_BASE: macro to fill in the page_frame_base array. this +; array contains the selector:offset into page table. The selector is already +; initialised. So the offset of each of the physical pages into the page +; table needs to be filled in. +; +; ENTRY: SI = INDEX INTO _page_frame_base, also physical page # +; BX = Segment of physical page +; +;****************************************************************************** +init_page_frame_base MACRO +; + push si + push bx +; + shl si,2 ; convert index into offset in dword array +; + shr bx,6 ; convert segment into page table offset + ; since there is 1 dword entry for each 4k + ; + mov _page_frame_base[si],bx ; fill this in +; + pop bx + pop si +; + ENDM + +;****************************************************************************** +;**init_MAPPABLE_PAGES: macro to fill the _mappable_pages array. this array +; contains the segment and physical page number of all the mappable physical +; pages. +; +; ENTRY: SI = INDEX INTO _page_frame_base, also physical page # +; BX = Segment of physical page +; DI = Index into _mappable_pages +; +;****************************************************************************** +init_mappable_pages MACRO +; + push di +; + shl di,2 ; convert index into offset in dword array +; + mov _mappable_pages[di],bx ; fill in segment + mov _mappable_pages[di][2],si ; and physical page number +; + pop di +; + ENDM + +;****************************************************************************** +;**init_MAPPABLE_INDEX: macro to fill in EMM_MPIndex array. This array +; contains a cross reference for the memory from 4000h to 10000h into the +; mappable_pages array. There is an entry for each 16k page. The pages in +; this range which are not mappable are initialised to -1. The ones which +; are mappable are initialised to the index into the mappable_pages array +; for the entry which represents this page +; +; ENTRY: DI = Index into _mappable_pages +; BX = Segment of physical page +; +;****************************************************************************** +init_mappable_index MACRO +; + push ax + push bx +; + shr bx,10 ; convert segment to 16k page # + sub bx,CONV_STRT_PG ; first page in EMM_MPIndex array is 16 +; + mov ax,di ; to extract the lower byte + mov _EMM_MPIndex[bx],al ; fill in index +; + pop bx + pop ax +; + ENDM + +;****************************************************************************** +; INVALIDATE_MAPPABLE_PAGE_ENTRY: macro to remove the page from the mappable +; page temporary list we are using. this is to facilitate the recognition +; of pages above A000 which are not page frame pages. When we recognise page +; frame pages we invalidate them so that the subsequent pass for pages doesn't +; include these. +; +; ENTRY: BX = Segment of physical page +;****************************************************************************** +inv_mpbl MACRO +; + push bx +; + shr bx,10 ; convert segment to 16k page # + mov cs:mappable_segs[bx],PAGE_NOT_MAPPABLE +; + pop bx +; + + ENDM + +; +LAST segment USE16 + assume cs:LAST, ds:DGROUP, es:DGROUP + +;****************************************************************************** +; LOCAL VARIABLES +;****************************************************************************** +first_sys_ppage dw 0ffffh ; physical page number of first system page + + page +;****************************************************************************** +; +; CODE FOR INITIALISATION +; +;****************************************************************************** + + + page +;****************************************************************************** +; EMM_Init - initialization routine for EMM. +; Patches int 67h vector. +; +; ENTRY: none +; +; EXIT: EMM vector initialized. +; EMM data structures initialized +; NC => no errors +; C => errors +; +; USED: none +; +;****************************************************************************** +EMM_Init proc near +; + pusha + push ds + push es +; +; set DS,ES to DGROUP segment +; + mov ax,seg DGROUP + mov ds,ax + mov es,ax +; + cld ; strings foward +; +; init EMM status +; + mov [_EMMstatus],0 + +; +; set total # of EMM pages +; + mov cx,[pool_size] ; CX = kbytes of expanded memory + shr cx,4 ; CX = # of EMM pages available + mov [_total_pages],cx ; pages total +; +; init ptrs for _emm_page, _emm_free and _pft386 +; + shl cx,1 ; CX = bytes in total_pages words + +ifndef NOHIMEM +else + mov ax,seg VDATA + sub ax,seg DGROUP + shl ax,4 ; convert into offset from dgroup + add ax,offset VDATA:vdata_begin + mov [_emm_page],ax +endif + + + mov ax,[_emm_page] ; AX = ptr to emm_page array + add ax,cx ; AX = ptr to word just past emm_page[] + mov [_emm_free],ax ; set ptr for emm_free[] + add ax,cx ; AX = ptr to word just past emm_free[] + mov [_pft386],ax ; set ptr for _pft386[] + shl cx,1 ; CX = bytes in total_pages dwords + add ax,cx ; AX = ptr to word just past _pft386[] + mov [_emm_brk],ax ; set break address for emm data + shr cx,2 ; CX = total_pages again +; +; init free pages array +; + mov [_free_count],cx ; all pages free initially + mov [_free_top],0 ; top ptr pts to first free page + mov di,[_emm_free] ; ES:DI pts to _emm_free[0] + mov bx,[_free_top] ; BX = current top of free list + shl bx,1 + add di,bx ; ES:DI pts to begin of free page area + xor ax,ax ; start with EMM page#0 +EMMP_loop: ; copy free pages into _emm_free + stosw ; store EMM page# + inc ax ;(0.02) increment page# + loop EMMP_loop ;Q: all entries in _emm_free[] ? + ; N: do next page. +; +; fix _page_frame_pages to be a maximum of 4 (for the LIM 3.2 frame) +; + cmp [_page_frame_pages],4 + jbe EMIN_1 + mov [_page_frame_pages],4 +EMIN_1: +; +; See validity of page frame +; + test [_PF_base],3ffh ; if any of these bits are set it is + ; invalid + jne EMIN_2 ; + cmp [_PF_base],0E400h ; in the ROM area + jae EMIN_2 ; also invalid + cmp [_PF_base],0C000h ; or in the video area + jnb EMIN_3 ; +EMIN_2: +; +; Page Frame invalid, set it to FFFFh and _page_frame_pages to 0 +; + mov [_PF_base],0FFFFh + mov [_page_frame_pages],0 +; +EMIN_3: +; +; setting up _page_frame_base +; _mappable_pages +; _EMM_MPIndex +; _physical_page_count +; _mappable_page_count +; +; +; +; ----------------- ----------------- ----------------- +; | for pages | | for pages | | |FC00h +; | below | | below | |---------------| +; | A000h | | A000h | | | +; ----------------- ----------------- | | +; | | | | | . | +; | for pages | | for pages | | . | +; | above | | above | | . | +; | A000h | | A000h | <-- | | +; | | | | | |---------------| +; ----------------- ----------------- | | |4800h +; | for page frame| | for page frame| | |---------------| +; | pages even if | | pages only if | |------- |4400h +; | they don't | | they exist | |---------------| +; | exist | | | | |4000h +; ----------------- ----------------- ----------------- +; +; _page_frame_base _mappable_pages EMM_MPIndex +; +; Each entry reps Each entry reps Each entry reps +; a physical page. a mappable ph. page a system page +; +; DWORD. DWORD Byte +; +; 1st WORD: offset 1st WORD: segment Index into +; into page table of ph. page _mappable_pages +; which reps the page +; 2nd WORD: sel. 2nd WORD: physical +; of page table page # of ph. page +; +; +; 1. Set up for the page frame pages. Note that they may or may not exist. +; Even if they do not exist entries must be set up for them in the +; _page_frame_base. +; + ; + ; initialise indexes. + ; + xor si,si ; index into _page_frame_pages + ; thus also physical page number + xor di,di ; index into _mappable_pages + ; + ; set up for page frame pages + ; + mov cx,[_page_frame_pages] ; get number + jcxz EMIN_5 ; if none exist then skip next portion + ; + mov bx,[_PF_base] ; get page frame base + ; + ; the setup loop: + ; +EMIN_4: + init_page_frame_base + init_mappable_pages + init_mappable_index + inv_mpbl + ; + ; update counters for next entry + ; + inc si + inc di + add bx,0400h + ; + ; and loop back + ; + loop EMIN_4 +; +EMIN_5: +; +; 2. If page frame pages were less than 4 then also we should set aside +; four entries in the physical page array +; + mov si,4 +; +; 3. Setup for the mappable pages above A000h. Search the mappable_segs +; array for mappable pages above A000h and for each mappable page make +; an entry in the arrays +; + ; + ; setup the segment and the count of pages we have to look for. also + ; the index into the mappable_segs array + ; + mov bx,0A000h ; segment + mov dx,bx ; + shr dx,10 ; page # corresponding to segment + ; + mov cx,64 ; max page # + sub cx,dx ; + ; + ; setup loop +EMIN_6: + ; + ; see if page mappable + ; + xchg dx,bx + cmp cs:mappable_segs[bx],PAGE_MAPPABLE ; + xchg dx,bx + jnz EMIN_7 + ; + ; page mappable. set up entries for it + ; + init_page_frame_base ; set up the page_frame_base entry + init_mappable_pages ; set up the mappable_pages entry + init_mappable_index ; set up the EMM_MPIndex + ; + ; update counters for next entry + ; + inc si ; these two are only updated + inc di ; if an entry is found +EMIN_7: + inc dx ; and these two are updated in + add bx,0400h ; any case + ; + ; and loop back + ; + loop EMIN_6 + +; +; 4. Finally set up for the system pages +; + ; + ; store the physical page # of the 1st system page. + ; + mov cs:[first_sys_ppage],si + ; + ; setup the segment and the count of pages we have to look for. also + ; the index into the mappable_segs array + ; + mov bx,04000h ; segment + mov dx,bx ; + shr dx,10 ; page # corresponding to segment + ; + mov cx,40 ; max page # + sub cx,dx ; + ; number of pages to be examined + ; + ; setup loop +EMIN_8: + ; + ; see if page mappable. + ; + xchg dx,bx + cmp cs:mappable_segs[bx],PAGE_MAPPABLE ; + xchg dx,bx + jnz EMIN_9 + ; + ; page mappable. set up entries for it + ; + init_page_frame_base ; set up the page_frame_base entry + init_mappable_pages ; set up the mappable_pages entry + init_mappable_index ; set up the EMM_MPIndex + ; + ; update counters for next entry + ; + inc si ; these two are only updated + inc di ; if an entry is found +EMIN_9: + inc dx ; and these two are updated in + add bx,0400h ; any case + ; + ; and loop back + ; + loop EMIN_8 +; +; 5. finally use the indexes to fill up the counts of the number of entries in +; each array. +; + mov [_physical_page_count],si + mov [_mappable_page_count],di +; +; +; 6. and the pages in a context and the number of bytes needed to save a +; context. +; + inc si ; cntxt_pages = (physical_page_count + ; + 1) & NOT 1 + and si, NOT 0001h ; to round up si to higher even # + mov [_cntxt_pages],si ; number of pages in a context +; + shl si,1 + add si,2 ; cntxt_bytes = cntxt_pages*2 + 2 + mov [_cntxt_bytes],si ; +; + +; +; initialize FRS_array +; + lea si,FRS_array ; DS:SI <-- FRS_array + mov [si.FRS_alloc], 1 ; mark FRS set 0 as allocated + mov [CurRegSetn], 0 ; use FRS set 0 + mov [FRS_free], FRS_COUNT-1 ; one less FRS set + mov word ptr [CurRegSet], SI; save current FRS pointer + +; +; NOW for some Handle 0 initialisation. We have to reclaim the pages we +; released to the emm page pool from the conventional memory. This is +; easy. These happen to be the first k pages in the emm page pool. We +; need to fix the following data structures to reclaim these. +; +; k pages need to be transferred to emm_page array from emm_free array +; and emmpt_start, _free_top, _free_count and _handle_table and _handle_count +; updated + ; + ; find out the number of pages to be reclaimed + ; + mov cx,[sys_size] ; in kb + shr cx, 4 ; convert to number of 16k pages + ; + ; transfer these many pages from the emm_free array to the emm_pages array + ; + push cx + ; + mov si,_emm_free ; + add si,_free_top ; + add si,_free_top ; get offset to free page + ; + mov di,_emm_page ; + add di,_emmpt_start ; + add di,_emmpt_start ; get offset to next available loc in + ; emm_page + ; + cld + rep movsw ; transfer the pages over + ; + pop cx + ; + ; fix entry for handle 0 in handle table + ; + mov dx, [_emmpt_start] + mov _handle_table[0],dx ; offset into emm_page array + mov _handle_table[2],cx ; number of pages + ; + ; handle_count needs to be incremented to indicate that handle 0 is + ; allocated + ; + inc [_handle_count] + ; + ; fix ptr in emm page tracking arrays + ; + add [_emmpt_start],cx + add [_free_top],cx + sub [_free_count],cx +; +; Initialise FRS initialisation +; +; di = pointer into FRS. bx = physical page number. si = pointer into emm_page +; cx = number of pages mapped. +; + mov si,_handle_table[0] ; get pointer into emm_page + shl si,1 ; emm_page is a word array + add si,[_emm_page] ; + ; + GET_FRS_WINDOW di ; get pointer to FRS area + + mov bx,cs:[first_sys_ppage] + shl bx,1 + add di,bx ; + ; + cld + rep movsw + ; +; +; the way we have allocated the pages we don't need to update the Page table +; the pages that have been mapped +; +; init ELIM h/w emulation (DMA PORTS) +; + call InitELIM + +; +; init EMM_PTE - ptrs to EMM pages +; + call InitEPage +; +; leave - no errors +; + pop es + pop ds + popa +; + xor ax,ax + clc + ret +; +EMM_Init endp + +; +LAST ends + + end diff --git a/v4.0/src/MEMM/MEMM/EMMMES.ASM b/v4.0/src/MEMM/MEMM/EMMMES.ASM new file mode 100644 index 0000000..1036a66 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EMMMES.ASM @@ -0,0 +1,210 @@ + + + page 58,132 +;****************************************************************************** + title EMMMES - messages for MEMM +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EMMMES - messages for MEMM +; +; Version: 0.05 +; +; Date: May 24,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 05/24/86 Original +; 06/26/86 0.02 changed version #. +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/06/86 0.04 changed version #. +; 07/06/86 0.04 changed assume to DGROUP +; 07/06/86 0.04 moved some messages to LAST +; 07/08/86 0.04 Changed messages for incorrect machine +; 07/09/86 0.05 changed version displayed version# to 3.20. +; +;****************************************************************************** +.lfcond +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public InitMess + public InstallMess + public ISizeMess + public ExtSizeMess + public SysSizeMess + public PFBAMess + public ActiveMess + public InactiveMess + public AutoMess + public POE_Mess + public POE_Num + public POE_Len + public EXCPE_Mess + public EXCPE_Num + public EXCPE_CS + public EXCPE_EIP + public EXCPE_ERR + public EXCPE_Len + public InvParm + public InvPFBA + public InvMRA + public Adj_Size + public InsfMem + public Incorrect_DOS + public Incorrect_PRT + public Already_Inst + public PFWarning + public No_PF_Avail + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include ascii_sm.equ + include vdmseg.inc + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +;****************************************************************************** +; +; LAST Segment messages +; +;****************************************************************************** +; +LAST segment + +InitMess db CR,LF + db "MICROSOFT Expanded Memory Manager 386 Version 4.00",CR,LF + db "(C) Copyright MICROSOFT Corporation 1988",CR,LF + db "$" + +InstallMess db "EMM386 Installed.", CR,LF + db " Extended memory allocated: " +ExtSizeMess db " KB",CR,LF + db " System memory allocated: " +SysSizeMess db " KB",CR,LF + db " " + db "--------",CR,LF + db " Expanded memory available: " +ISizeMess db " KB",CR,LF + db " Page frame base address: " +PFBAMess db "XX000 H",CR,LF + db "$" + +ActiveMess db "EMM386 Active.",CR,LF + db CR,LF + db "$" + +InactiveMess db "EMM386 Inactive.",CR,LF + db CR,LF + db "$" + +AutoMess db "EMM386 is in Auto mode.",CR,LF + db CR,LF + db "$" + +; +; install error messages +; + +InvParm db "Invalid parameter specified.",CR,LF + db "$" + +InvPFBA db "Page Frame Base Address adjusted.",CR,LF + db "$" + +InvMRA db "Mapping Register Address adjusted.",CR,LF + db "$" + +Adj_Size db "Size of expanded memory pool adjusted.",CR,LF + db "$" + +PFWarning db "WARNING - " + db "Option ROM or RAM detected within page frame." + db CR,LF + db CR,LF + db BEL + db "$" + +InsfMem db "EMM386 not installed - insufficient memory.",CR,LF + db BEL + db CR,LF + db "$" + +Incorrect_DOS db "EMM386 not installed - incorrect DOS version.",CR,LF + db BEL + db CR,LF + db "$" + +Incorrect_PRT db "EMM386 not installed - incorrect machine type.",CR,LF + db BEL + db CR,LF + db "$" + +No_PF_Avail db "EMM386 not installed - " + db "unable to set page frame base address.",CR,LF + db BEL + db CR,LF + db "$" + +Already_Inst db "EMM386 already installed.",CR,LF + db BEL + db CR,LF + db "$" + +LAST ends + + page +;****************************************************************************** +; +; _DATA Segment messages +; +;****************************************************************************** +; +_DATA segment + +; +; run time error messages +; +POE_Mess db CR,LF + db BEL + db "EMM386 Privileged operation error #" +POE_Num db "xx -",CR,LF + db "Deactivate EMM386 and Continue (C) or reBoot (B)" + db " (C or B) ? " +POE_Len = $-POE_Mess + db "$" + +EXCPE_Mess db CR,LF + db BEL + db "EMM386 Exception error #" +EXCPE_Num db "xx @" +EXCPE_CS db "xxxx:" +EXCPE_EIP db "xxxxxxxx Code " +EXCPE_ERR db "xxxx" + db CR,LF,"Press enter to reboot" +EXCPE_Len = $-EXCPE_Mess + db "$" + +; +_DATA ends + + end + + diff --git a/v4.0/src/MEMM/MEMM/ERRHNDLR.ASM b/v4.0/src/MEMM/MEMM/ERRHNDLR.ASM new file mode 100644 index 0000000..a675868 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ERRHNDLR.ASM @@ -0,0 +1,385 @@ + + + page 58,132 +;****************************************************************************** + TITLE ErrHndlr - Error Handler +;****************************************************************************** +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: ErrHndlr - Recover from exception and priveledged operation errors +; +; Version: 0.04 +; +; Date: June 6,1986 +; +; Authors: Brad Tate +; +;****************************************************************************** +; +; CHANGES: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------ +; 06/06/86 Original +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 06/28/86 0.02 Removed STI at end of ErrHndlr +; 06/28/86 0.02 Changed error # display to leading zeroes +; 07/06/86 0.04 Changed assume to DGROUP +; +;****************************************************************************** + page +;****************************************************************************** +; +; Functional description: +; +; This module contains the code that displays an error message and +; asks the user to continue or reboot. +; +;****************************************************************************** + page +.386P +; + include vdmseg.inc + include vdmsel.inc + include vm386.inc + include kbd.inc +;****************************************************************************** +; Public Declarations +;****************************************************************************** +; + public ErrHndlr ; Display message and continue or reboot + public Error_Flag +;****************************************************************************** +; Externs +;****************************************************************************** +_TEXT segment + extrn RetReal:near ; return to real mode + extrn egetc:near ; get keyboard character + extrn WaitKBD:near ; wait for keyboard ready +_TEXT ends + +_DATA segment + extrn powr10:word ; power of 10's table + extrn POE_Mess:byte ; privileged operation error + extrn POE_Num:byte ; where to put error code + extrn POE_Len:abs ; length of message + extrn EXCPE_Mess:byte ; exception error message + extrn EXCPE_Num:byte ; where to put error code + extrn EXCPE_CS:byte ; where to put CS + extrn EXCPE_EIP:byte ; where to put EIP + extrn EXCPE_ERR:byte ; where to put ERR + extrn EXCPE_Len:abs ; length of message +_DATA ends +; +romdata segment use16 at 40h + org 71h +fBreak db ? +fReset dw ? +romdata ends +; +;****************************************************************************** +; Equates +;****************************************************************************** +; +MASTER = 0A1H ; Master interrupt i/o port +SLAVE = 021H ; Slave interrupt i/o port +NMI = 070H ; Non-Maskable interrupt i/o port +DIS_MSTSLV = 00H ; Value to write to disable master/slave +DIS_NMI = 080H ; Value to write to disable NMI +ENA_NMI = 008H ; Value to write to enable NMI +B = 48 ; make code for B +C = 46 ; make code for C +ENTER = 28 ; make code for enter key +ATTR = 07 ; attribute for write string +WRSTR = 1301h ; write string function code (format 1) +CPOSN = 5*256+0 ; cursor position to write +; +; +;****************************************************************************** +; LOCAL DATA +;****************************************************************************** +_DATA segment +Error_Flag dw 0 ; flags for Instruction Prefixes +masterp db 0 ; save master port value +slavep db 0 ; save slave port value +mode db 0 ; save mode +boot db 0 ; value to reboot +continue db 0 ; value to continue + +GPsavERR dw 0 ; GP fault Error Code save +GPsavEIP dd 0 ; GP fault EIP save +GPsavCS dw 0 ; GP fault CS save + +_DATA ends +; +;****************************************************************************** +; +; ErrHndlr - displays the appropriate error message and prompts the +; user for a character to continue or reboot. The screen +; is cleared by this routine. If the user chooses to +; continue, the system is in real mode. +; +; entry: ax = 0 => Privileged operation error +; ax = 1 => Exception error +; bx = error number to display +; +; exit: either reboot, or exit in "real" mode with CLI +; +; used: none +; +; stack: +; +;****************************************************************************** +_TEXT segment + ASSUME CS:_TEXT, DS:DGROUP, ES:DGROUP +ErrHndlr proc near +; +; save fault infos +; + push eax + push ds + push VDMD_GSEL + pop ds + mov eax, dword ptr [bp.VTFO] ; error code + mov [GPsavERR], ax + mov eax, dword ptr [bp.VTFOE+VMTF_EIP] ; EIP + mov [GPsavEIP], eax + mov ax, word ptr [bp.VTFOE+VMTF_CS] ; CS + mov [GPsavCS], ax + pop ds + pop eax + + call RetReal ; return to real mode +; + push ax + push bx + push cx + push dx + push bp + push di +; + push ax ; save input to this routine + in al,MASTER ; get value of master interrupt port + mov [masterp],al ; save it + in al,SLAVE ; get value of slave interrupt port + mov [slavep],al ; save it + mov al,DIS_MSTSLV ; value to disable master/slave int + out MASTER,al ; disable master + out SLAVE,al ; disable slave + mov al,DIS_NMI ; value to disable NMI + out NMI,al +kbdbusy: + call egetc ; q: is there stuff in keyboard buffer? + jnz kbdbusy ; y: get it and pitch it + ; n: continue + pop ax ; get entry condition + or ax,ax ; q: privileged error? + jnz excep ; n: exception error + mov bp,offset DGROUP:POE_Mess ; y: privileged error + mov cx,POE_Len + mov di,offset DGROUP:POE_Num; error number location + mov ax,bx ; error number in ax + call b2asc10 ; convert to ascii + mov [boot],B ; key to boot + mov [continue],C ; key to continue + jmp skip_exc ; skip exception stuff +excep: + mov bp,offset DGROUP:EXCPE_Mess ; n: load up exception error + mov cx,EXCPE_Len ; length of msg + mov di,offset DGROUP:EXCPE_Num ; error number location + mov ax,bx ; error number in ax + call b2asc10 ; convert to ascii + mov di,offset DGROUP:EXCPE_CS + mov ax,[GPsavCS] + call b2asc16 + mov di,offset DGROUP:EXCPE_EIP + mov eax,[GPsavEIP] + ror eax,16 + call b2asc16 + ror eax,16 + call b2asc16 + mov di,offset DGROUP:EXCPE_ERR + mov ax,[GPsavERR] + call b2asc16 + mov [boot],ENTER ; key to reboot + mov [continue],0ffh ; can't continue +skip_exc: + mov ah,0fh ; read video state + int 10h + mov [mode],al ; save mode +; mov ax,3 ; set to mode 3 +; int 10h ; standard 80 x 25 color + mov dx,CPOSN ; cursor position + mov bl,ATTR ; attribute + mov ax,WRSTR ; write string function code + int 10h ; do it + cli ; make sure int 10 didn't enable +key_loop: + call egetc ; get a character + jz key_loop ; nothing there yet + cmp al,[continue] ; q: continue? + je err_cont ; y + cmp al,[boot] ; q: boot? + jne key_loop ; n: try again +;****************************************************************************** +; +; Reboot system +; +;****************************************************************************** + assume ds:romdata + mov ax,romdata + mov ds,ax ; ds = romdata segment + mov [freset],0 ; cold restart + mov al,0fh or 80h ; shutdown byte address/disable NMI + out 70h,al ; write CMOS address + jmp short $+2 ; delay + mov al,0h ; shutdown code 0 = processor reset + out 71h,al ; write shutdown code to shutdown byte + call WaitKBD ; wait for 8042 to accept command + mov al,0feh ; feh = pulse output bit 0 (reset) + out KbStatus,al ; reset processor + hlt + assume ds:DGROUP +; +err_cont: + xor ah,ah ; ah = 0 to set video mode + mov al,[mode] ; restore their mode + int 10h + cli ; turn them off... +; +; restore master, slave, and NMI +; + mov al,[masterp] ; get value of master interrupt port + out MASTER,al ; restore it + mov al,[slavep] ; get value of slave interrupt port + out SLAVE,al ; restore it + mov al,ENA_NMI ; value to enable NMI + out NMI,al +; + pop di + pop bp + pop dx + pop cx + pop bx + pop ax + ret +ErrHndlr endp + +page +;****************************************************************************** +; +; b2asc10 - converts binary to ascii decimal and store at _TEXT:DI +; stores 2 ascii chars (decimal # is right justified and +; filled on left with 0s) +; +; entry: ax = binary number +; ds:DGROUP +; ds:di = place to store ascii chars. +; +; exit: ASCII decimal representation of number stored at _TEXT:DI +; +; used: none +; +; stack: +; +;****************************************************************************** +; +b2asc10 proc near +; + push ax + push bx + push cx + push dx + push si + push di +; + mov si,2 ; pointer to base 10 table + mov bl,1 ; leading zeroes on +; +; convert binary number to decimal ascii +; +b2_loop: + xor dx,dx ; clear word extension + mov cx,powr10[si] + div cx ; divide by power of 10 + or bl,bl + jnz b2_ascii +; + or ax,ax ; q: zero result? + jnz b2_ascii ; n: go convert to ascii +; + mov al,' ' ; y: go blank fill + jmp b2_make_strg ; +; +b2_ascii: + add al,'0' ; put into ascii format + mov bl,1 ; leading zeroes on +; +b2_make_strg: + mov ds:[di],al ; put ascii number into string + xchg ax,dx + inc di ; increment buffer string pointer + dec si ; decrement power of 10 pointer + dec si ; + jge b2_loop ; Q: Last digit? N: Jump if not +; + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret ; *** return *** +; +b2asc10 endp +; +;****************************************************************************** +; +; b2asc16 - converts binary to hexidecimal and store at _TEXT:DI +; stores 4 ascii chars (# is right justified and +; filled on left with 0s) +; +; entry: ax = binary number +; ds:DGROUP +; ds:di = place to store ascii chars. +; +; exit: ASCII hexidecimal representation of number stored at _TEXT:DI +; +; used: none +; +; stack: +; +;****************************************************************************** +; +b2asc16 proc near + + push ax + push bx + push cx + + mov cx,4 +b2asc16_loop: + mov bl,ah + shr bl,4 + add bl,'0' + cmp bl,'9' + jbe b2asc16_skip + add bl,'A'-'9'-1 +b2asc16_skip: + mov ds:[di],bl + shl ax,4 + inc di + loop b2asc16_loop + + pop cx + pop bx + pop ax + ret + +b2asc16 endp + +_TEXT ENDS + END + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/EXTPOOL.ASM b/v4.0/src/MEMM/MEMM/EXTPOOL.ASM new file mode 100644 index 0000000..de7b492 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EXTPOOL.ASM @@ -0,0 +1,187 @@ + + + page 58,132 +;****************************************************************************** + TITLE EXTPOOL - MODULE to manage a pool of extended memory +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: EXTPOOL - Manage a pool of extended memory. +; +; Version: 0.01 +; +; Date: Sep 1, 1988 +; +; Author: ISP (ISP) +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +;****************************************************************************** +; Functional Description: +; +; "Fixit Orders" Crisis mode file. We need to ship data structures up hi. +; So at init time we get a pool of extended memory and manage it for the +; fixit routine. Services provided include initialise, allocate and +; blkmov to the memory. +; +;****************************************************************************** +.lfcond +.386p + + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** + public pool_initialise + public get_buffer + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + +;****************************************************************************** +; INCLUDE FILES +;****************************************************************************** + include vdmseg.inc ; segment definitions + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +; + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +;************************************************************************* +; +; DATA +; +;************************************************************************* + +LAST SEGMENT + +ext_start dw 0000h ; start of the pool of extended memory + dw 0010h ; 24 bit address + +ext_size dw 0 ; size + dw 0 ; + +LAST ENDS + +;************************************************************************* +; +; CODE +; +;************************************************************************* +LAST SEGMENT +assume cs:LAST, DS:DGROUP, ES:DGROUP + + +;****************************************************************************** +;*** Pool Initialise *** Give this memory manager the memory it is to play ; +; with. ; +; ; +; INPUTS: AX = start offset of the extended memory in K ; +; CX = size of the memory ; +; ; +; OUTPUTS: None ; +; ; +; USES: None ; +; ; +; AUTHOR: ISP (ISP) Sep 1, 1988 ; +; ; +;*****************************************************************************; + +Pool_Initialise proc near +; + push dx + push cx + push ax +; + push cx ; save size of memory + xor dx,dx + mov cx,1024 + mul cx ; dx:ax size in bytes offset from 1M +; + add ax,cs:[ext_start] ; add it to 1M + adc dx,cs:[ext_start+2] ; +; + mov cs:[ext_start],ax ; + mov cs:[ext_start+2],dx ; +; + pop ax ; get size into ax + xor dx,dx ; + mul cx +; + mov cs:[ext_size],ax + mov cs:[ext_size+2],dx +; + pop ax + pop cx + pop dx +; + ret +; +Pool_Initialise endp + + + +;****************************************************************************** +;***Get buffer*** Give some poor beggar the memory he is asking for ; +; ; +; INPUTS: cx = size of buffer required in bytes ; +; ; +; OUTPUTS: DX:AX = address of buffer ; +; cx = size allocated +; ; +; USES: None ; +; ; +; AUTHOR: ISP (ISP) Sep 1, 1988 ; +; ; +;*****************************************************************************; + +Get_Buffer proc near +; + ; + ; assume that the memory is present, put start address in dx:ax + ; + mov dx,cs:[ext_start+2] + mov ax,cs:[ext_start] + ; + ; then proceed to determine if it really exists + ; + push eax + xor eax,eax + mov ax,cx + cmp eax, dword ptr cs:[ext_size] + ja no_mem + ; + ; it does exist, adjust the size and the start address + ; + sub dword ptr cs:[ext_size],eax + add dword ptr cs:[ext_start],eax +; + pop eax + clc + ret + +no_mem: + pop eax + stc + ret +Get_buffer endp + +LAST ENDS + end diff --git a/v4.0/src/MEMM/MEMM/I286.ASM b/v4.0/src/MEMM/MEMM/I286.ASM new file mode 100644 index 0000000..8eb2102 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/I286.ASM @@ -0,0 +1,312 @@ + + +page 58,132 +;****************************************************************************** + TITLE i286.asm - Support Routines for protected mode system +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: i286.asm - Support Routines for protected mode system +; +; Version: 0.02 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 02/05/86 A added is286, is386 +; 05/12/86 B Cleanup and segment reorganization +; 06/03/86 C added push/pop es to Init_GDT and changed Ring 0 +; stack to STACK0 and STACK0_SIZE. +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; +;****************************************************************************** +; +; Functional Description: +; +; Anthony Short +; 26th Dec 1985 +; +; DESCRIPTION +; +; These routines manage the various 286 memory management +; tables and manipulate descriptors and selectors. +; +; The routines which deal with descriptors use the following +; register usage conventions: +; +; BX - selector of required descriptor. The selector may +; have RPL bits present, the routines ignore them. +; +; CX - SIZE IN BYTES of segment. NOTE: descriptors contain +; limits, not sizes (limit = size - 1). Since everyone +; else talks sizes, these routines do too, and do their +; own conversion. +; +; DX - second selector when needed +; +; AH - access rights byte +; +; AL, DX - 24 bit physical address +; +; ES:0 - pointer to the desired descriptor table. +; +; All the routines which manipulate descriptors are callable +; in both real and protected mode. +; +; In general all registers are preserved. +; +; The following routines are provided: +; +; SetDescInfo - set descriptor information +; SetSegDesc - set segment descriptor information +; +; SegTo24 - convert segment number to 24 bit addr +; SegOffTo24 - convert seg:offset to 24 bit addr +; +; InitGdt - set up parts of GDT which cannot easily +; be initialised statically. +; +; WARNING This code is 286 specific, it will NOT run on an 8088. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + + + include VDMseg.inc + include VDMsel.inc + include desc.inc + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +GDT segment + extrn GDTLEN:abs +GDT ends + +IDT segment + extrn IDTLEN:abs +IDT ends + +TSS segment + extrn TSSLEN:abs +TSS ends + +LAST SEGMENT + + assume cs:LAST + +;** SetDescInfo - 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. + + public SetDescInfo +SetDescInfo 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 +SetDescInfo endp + + +;** SetSegDesc - set segment 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 = size +; 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. + + public SetSegDesc +SetSegDesc proc near + dec cx ; convert size to limit + call SetDescInfo ; set descriptor information + inc cx ; restore size + ret +SetSegDesc endp + + +;** SegTo24 - convert segment to 24 bit physical address +; +; The real mode segment number is convert to a 24 bit addr +; +; ENTRY AX = segment +; 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. + public SegTo24 +SegTo24 proc near + mov dl,ah + shr dl,4 ; DH = high byte of 24 bit addr + xchg ax,dx ; AH = high byte, DX = segment + shl dx,4 ; DX = low word of 24 bit addr + ret +SegTo24 endp + + +;** SegOffTo24 - 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. + + public SegOffTo24 +SegOffTo24 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 +SegOffTo24 endp + + + page +;****************************************************************************** +; IS286 - return type of processor (286 vs. 8088/86). 386 returns 286. +; This routine relies on the documented behaviour of the PUSH SP +; instruction as executed on the various processors. This routine +; may be called from any mode on any processor, provided a proper +; stack exists. +; +; ENTRY: (none) +; EXIT: ZF = 1 if 8088/86 +; ZF = 0 if 286/386 +; USED: flags +; STACK: 6 bytes +;------------------------------------------------------------------------------ + public Is286 +Is286 proc near + push bp + push sp + mov bp,sp + cmp bp,[bp] ; compare SP with saved SP + pop bp ; clean SP off stack + pop bp ; restore BP + ret ; *** RETURN *** +Is286 endp + page +;****************************************************************************** +; Is386 - return type of processor (386 vs. 8088/86/286). +; This routine relies on Intel-approved code that takes advantage +; of the documented behavior of the high nibble of the flag word +; in the REAL MODE of the various processors. The MSB (bit 15) +; is always a one on the 8086 and 8088 and a zero on the 286 and +; 386. Bit 14 (NT flag) and bits 13/12 (IOPL bit field) are +; always zero on the 286, but can be set on the 386. +; +; For future compatibility of this test, it is strongly recommended +; that this specific instruction sequence be used. The exit codes +; can of course be changed to fit a particular need. +; +; CALLABLE FROM REAL MODE ONLY - FAR ROUTINE +; +; ENTRY: (none) +; EXIT: STC if 8088/86/286 +; CLC if 386 +; USED: none +; STACK: 6 bytes +;------------------------------------------------------------------------------ + public Is386 +Is386 proc FAR + push ax + pushf ; save entry flags +; + xor ax,ax ; 0000 into AX + push ax + popf ; try to put that in the flags + pushf + pop ax ; look at what really went into flags + test ax,08000h ;Q: was high bit set ? + jnz IsNot386_exit ; Y: 8086/8088 + mov ax,07000h ; N: try to set the NT/IOPL bits + push ax + popf ; ... in the flags + pushf + pop ax ; look at actual flags + test ax,07000h ; Q: any high bits set ? + jz IsNot386_exit ; N: 80286 + ; Y: 80386 +Is386_exit: + popf ; restore flags + clc ; 386 + jmp short I386_exit ; and leave + +IsNot386_exit: + popf ; restore flags + stc ; not a 386 + +I386_exit: + pop ax + ret ; *** RETURN *** + +Is386 endp + +LAST ends + + + end diff --git a/v4.0/src/MEMM/MEMM/I386.ASM b/v4.0/src/MEMM/MEMM/I386.ASM new file mode 100644 index 0000000..6065dbe --- /dev/null +++ b/v4.0/src/MEMM/MEMM/I386.ASM @@ -0,0 +1,240 @@ + + +page 58,132 +;****************************************************************************** + TITLE i386.asm - Support Routines for protected mode system +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: i386.asm - Support Routines for protected mode system +; +; Version: 0.04 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/21/86 0.02 Added clds just in case +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/06/86 0.04 changed assume to DGROUP +; +;****************************************************************************** +; +; DESCRIPTION +; +; These routines manage the various 386 memory management +; tables and manipulate descriptors and selectors. +; +; All the routines which manipulate descriptors are callable +; in both real and protected mode. +; +; In general all registers are preserved. +; +; The following routines are provided: +; +; SetPageEntry - set up an entry in a Page Directory on Page +; Table. +; +; GetPageEntry - retrieve a page dir/page table entry. +; +; InitPages - initialize page directory and page table. +; +; PageDirOff - convert 32 bit addr to page dir entry offset +; +; PageTableOff - convert 32 bit addr to page table entry offset +; +; WARNING This code is 386 specific, it will NOT run on an 8088. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + include page.inc + +;****************************************************************************** +; E X T E R N A L S +;****************************************************************************** +LAST SEGMENT +extrn SegTo24:near +LAST ENDS + + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N S +;****************************************************************************** +LAST SEGMENT + + assume cs:LAST,ds:DGROUP,es:DGROUP + +;** SetGateDesc - set up Gate Descriptor entry +; +; +; ENTRY DX,AX = 32 bit offset of target routine +; CX = target code segment selector +; ES:[DI] = points to table entry +; BL = access bits +; EXIT descriptor set. +; USES Flags, other regs preserved +; +; WARNING This code only works on a 386. It can be called in +; either mode. + + public SetGateDesc +SetGateDesc proc near +; + push ax + push di +; + cld ; stings foward +; + stosw ; store low word of offset + mov ax,cx + stosw ; store selector + mov al,0 + mov ah,bl + stosw ; store access rights + mov ax,dx + stosw ; store high word of offset +; + pop di + pop ax + ret +SetGateDesc endp + + +;** SetPageEntry - set up entry in Page Directory or Page Table +; +; +; ENTRY DX,AX = 32 bit address of page or page table +; ES:[DI] = page directory or table entry to set +; BX = access/status bits ( bits 0 - 11 ) +; EXIT ES:[DI] = next page directory or table entry +; USES Flags, other regs preserved +; +; WARNING This code only works on a 386. It can be called in +; either mode. + + public SetPageEntry +SetPageEntry proc near +; + push ax +; + cld ; strings foward +; + and bx,0FFFh ; turn off any bits in address range + or ax,bx ; mov status bits into AX + stosw ; store status and addr bits 12 - 15 + mov ax,dx ; AX = addr bits 16-31 + stosw ; store addr bits 16-31 +; + pop ax + ret +SetPageEntry endp + + +;** GetPageEntry - up entry in Page Directory or Page Table +; +; ENTRY ES:[DI] = page directory or table entry +; EXIT DX,AX = 32 bit address of page or page table +; BX = access/status bits (bits 0 - 11). +; USES Flags, other regs preserved +; +; WARNING This code only works on a 386. It can be called in +; either mode. + + public GetPageEntry +GetPageEntry proc near +; + mov ax,ES:[DI] ; AX = low word of entry + mov bx,ax ; get access/status rights bits + and bx,00FFFh ; turn off address bits +; + and ax,0F000h ; turn off status bits + mov dx,ES:[DI+2] ; get high word of addr +; + ret +GetPageEntry endp + + +;** PageDirOff - convert 32 bit linear address to page directory offset +; +; +; ENTRY EAX = 32 bit linear address +; EXIT DI = offset in page dir to appropriate entry +; USES Flags, other regs preserved +; +; WARNING This code only works on a 386. It can be called in +; either mode. + + public PageDirOff +PageDirOff proc near +; + db 66h + push bx ; push EBX + + db 66h + mov bx,ax ; EBX = EAX + + db 66h + shr bx,22 ; EBX[0:9] = EBX[22:31] = high 10 bits + shl bx,2 ; *4 for dword indexing into table + + mov di,bx ; DI = dir offset + + db 66h + pop bx ; pop EBX +; + ret +PageDirOff endp + + +;** PageTableOff - convert 32 bit linear address to page table offset +; +; +; ENTRY EAX = 32 bit linear address +; EXIT DI = offset in page table to appropriate entry +; USES Flags, other regs preserved +; +; WARNING This code only works on a 386. It can be called in +; either mode. + + public PageTableOff +PageTableOff proc near +; + db 66h + push bx ; push EBX + + db 66h + mov bx,ax ; mov EBX,EAX + + db 66h + shr bx,12 ; EBX[0:9] = EBX[12:21] = middle 10 bits + and bx,3FFh ; only EBX[0:9] + shl bx,2 ; *4 for dword indexing into table + + mov di,bx ; DI has table offset + + db 66h + pop bx ; pop EBX +; + ret +PageTableOff endp + + +LAST ends + + end diff --git a/v4.0/src/MEMM/MEMM/INIT.ASM b/v4.0/src/MEMM/MEMM/INIT.ASM new file mode 100644 index 0000000..44ab1c7 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/INIT.ASM @@ -0,0 +1,1123 @@ + + + page 58,132 +;****************************************************************************** + TITLE INIT - initialization code for MEMM +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: INIT - initialization code for MEMM +; +; Version: 0.05 +; +; Date: May 24,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 05/24/86 Original +; 06/18/86 0.01 Added AUTO as a valid config line parameter. +; 06/25/86 0.02 Added call to debug init. +; 06/27/86 0.02 Check for Mx length = 2 and only 2 +; 06/28/86 0.02 Change name from MEMM386 to MEMM +; 06/29/86 0.02 Size > 8192 were used instead of converted +; to 256 +; 07/03/86 0.04 Added TEXT_Seg +; 07/06/86 0.04 changed assume to DGROUP +; 07/06/86 0.04 moved init messages to LAST +; 07/10/86 0.05 added int15 patch and int67 patch here +; 07/20/88 removed debugger codes (pc) +; 07/29/88 removed ON/OFF/AUTO support +; +;****************************************************************************** +; Functional Description: +; This module allocates the pool of extended memory to be used for +; expanded memory, then call routines to initialize the data structures +; for EMM and VDM. +; +;****************************************************************************** +.lfcond +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public Init_MEMM386 + + public pool_size + public msg_flag + public Active_Status + public Auto_Mode + public dos_version + public TEXT_Seg + public STACK_Seg + public GDT_Seg + public IDT_Seg + public TSS_Seg + public driver_end + public powr10 + + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include vdmseg.inc + include vdmsel.inc ; for Deb386 Init + include desc.inc ; " " " + include emm386.inc + include driver.equ + include driver.str + include ascii_sm.equ +; +; maximum value for SIZE parameter +; +MAX_SIZE equ 32 * 1024 ; 32K => 32Meg + +; +MS_DOS equ 21h +PRINT_STRING equ 09h +GET_VERSION equ 30h +; +FALSE equ 0 +TRUE equ not FALSE +DOS3X_ADJ equ 1 ; DOS 3.x base memory adjustment + +; +; macro for printing messages located in LAST segment +; ENTRY: DX = offset LAST:message +; +PRINT_MSG macro + push ds + push seg LAST + pop ds ; ds = LAST + mov ah,PRINT_STRING + int MS_DOS ; output init message + pop ds + ENDM + + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +; +_DATA segment + + extrn PF_Base:word +; extrn himem_use:byte ;* this is defined in oemproc.asm since it + ; deals with memory so oem dependent + extrn ext_size:word ; size of extended memory allocated + extrn sys_size:word ; size of system memory allocated + +_DATA ends + +ABS0 segment use16 at 0 + org 4*15h ; int 15h vector +i15_vector dw 0 + dw 0 + + org 4*67h ; int 67h vector +i67_vector dw 0 + dw 0 +ABS0 ends + +; +R_CODE segment +extrn i15_Entry:near ; int15h patch code +extrn EMM_rEntry:near ; int67h patch code +extrn i15_Old:word ; old int15 vector +R_CODE ends + +; +_TEXT segment + + extrn Inst_chk_f:far ; check for MEMM already installed + extrn FarGoVirtual:far ; go to virtual mode + extrn get_token:near ; get token from command line + +_TEXT ends +; +LAST segment + + extrn VerifyMachine:near + extrn InitMess:byte + extrn InstallMess:byte + extrn ISizeMess:byte + extrn ExtSizeMess:byte + extrn SysSizeMess:byte + extrn PFBAMess:byte + extrn ActiveMess:byte + extrn InactiveMess:byte + extrn AutoMess:byte + extrn InvParm:byte + extrn InvPFBA:byte + extrn InvMRA:byte + extrn Adj_Size:byte + extrn InsfMem:byte + extrn Incorrect_DOS:byte + extrn Incorrect_PRT:byte + extrn Already_Inst:byte + extrn No_PF_Avail:byte + extrn PFWarning:byte + + extrn Is386:far ; check for 386 + extrn EMM_Init:near ; initialization for EMM data structs + extrn AllocMem:near ; allocate extended memory routine + extrn InitTab:near ; OEM init code for tables + extrn VDM_Init:near ; initialize VDM + extrn DeallocMem:near ; deallocate hi/extended memory routine + + extrn find_phys_pages:near ; find the mappable pages in 0-1M range + extrn exclude_segments:near ; exclude segments within a range + extrn estb_mach_state:near ; establish machine environment + +LAST ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + + page +;****************************************************************************** +; Data segment +;****************************************************************************** +_DATA segment +; +dos_version db 0h ; MS-DOS version +pool_size dw 0 ; size of EMM Pages Pool in kbytes +msg_flag dw 0 ; Message flag byte + +driver_end dw 0 ; end of driver -> driver brk address + dw seg LAST +powr10 dw 1,10,100,1000,10000 +max_arg_len equ 11 ; maximum length of argument on cmd line +arg_str db max_arg_len+1 dup(0) +; +; Active_Status is used to signal the termination condition for the +; driver. After the driver installs, Active_Status holds the +; current status (ON or OFF). +; Auto_Mode is set when MEMM is running in AUTO mode. +; +Active_Status db 0FFh ; 0 => OFF , non-zero => ON +Auto_Mode db 0h ; non-zero => auto mode + +; +; The following pointers are segment addresses for various segments +; +TEXT_Seg dw seg _TEXT ; current segment for _TEXT +STACK_Seg dw seg STACK ; current segment for STACK +GDT_Seg dw seg GDT ; current segment for GDT +IDT_Seg dw seg IDT ; current segment for IDT +TSS_Seg dw seg TSS ; current segment for TSS + +_DATA ends + + +;****************************************************************************** +; +; Code Segments +; +;****************************************************************************** +; +_TEXT segment + assume cs:_TEXT + + +;************************************************************************* +; +; get_token_far call get_token which must be near since it is +; also part of a .COM file +; +;************************************************************************* +get_token_far proc far + call get_token + ret +get_token_far endp +_TEXT ends + +LAST segment + assume cs:LAST, ds:DGROUP, es:DGROUP + + page +;****************************************************************************** +; Init - Initialization routine for MEMM. +; +; ENTRY: DS:BX pts to INIT request header. +; +; EXIT: AX = INIT status for request header +; if NO errors : +; MEMM initialized. +; if [ON] parameter specified on command line +; exit in Virtual mode and MEMM active. +; else ( [OFF] parameter specified ) +; exit in Real mode and MEMM inactive. +; if errors: +; Real Mode +; USED: none +; +;****************************************************************************** +Init_MEMM386 proc far + push bx ; BP+10 + push dx ; BP+8 + push bp ; BP+6 + push di ; BP+4 + push ds ; BP+2 + push es ; BP+0 + mov bp,sp +; +; set up DS = DGROUP and ES:BX to request header +; + push ds + pop es ; ES:BX pts to req hdr + mov ax,seg DGROUP + mov ds,ax ; DS = DGROUP + +; +; initialize break address to not install +; + mov word ptr ES:[bx.BRK_OFF],0000 ; set it + mov ax,seg R_CODE ; get brk addr segment + inc ax ; reserve dos link pointer + mov ES:[bx.BRK_SEG],ax ; break addr = cs - don't install + mov byte ptr es:[bx.NUM_UNITS],0 ; 0 - don't install +; +; verify that MEMM is not already installed +; + call Inst_chk_f + or ax,ax ; q: already installed? + jz chk_pt ; n: go check processor type + or [msg_flag],INS_ERR_MSG ; y: error + jmp IE_exit ; quit +; +; verify processor type +; +chk_pt: + call Is386 ;Q: is this a 386 ? + jnz inc_prc ; N: no, set error + ; Y: check machine type +; +; verify machine type +; +chk_mt: + stc ; Indicate this is verify from INIT + call VerifyMachine ;Q: is this a good machine to run on? + jnc chk_dos ; y: ok so far. go check dos version +inc_prc: + or [msg_flag],INC_PRC_MSG ; n: incorrect processor type + jmp IE_exit ; quit +; +; get DOS version - accept >= 3.1 +; +chk_dos: + push bx + mov ah,GET_VERSION + int MS_DOS ; get dos version # + mov [dos_version],al ; save it. + pop bx + cmp ax,4 ;Q: DOS 4.00 + je IE_parse ; Y: OK - continue install + cmp al,3 ;Q: DOS 3.xx ? + jl IE_dos_err ; N: return error + cmp ah,10 ;Q: current DOS >= 3.10 ? + jae IE_parse ; Y: OK - continue install +IE_dos_err: + or [msg_flag],INC_DOS_MSG ; N: set error and exit + jmp IE_exit +; +; parse command line for +; (1) requested size for expanded memory +; (2) page frame base address +; (3) I/O addresses for board emulations +; (4) Driver exit mode (virtual or real) +; +IE_parse: + les di,ES:[bx.ARG_PTR] ; ES:DI pts to config.sys command + ; line parameters + call parser ; parse the parameters + test [msg_flag],KILLER_MSG ;Q: any killer messages? + jz IE_mach_state ; N: go to establish machine state + jmp IE_exit ; Y: exit with error + +IE_mach_state: +; + push ds + pop es ; ES:DGROUP +; + call estb_mach_state ; since we are an environment, we need + ; to find the state we exist in right + ; now and maintain it. + test [msg_flag],KILLER_MSG ;Q: any killer messages? + jz IE_find_phys ; N:go to find physical pages + jmp IE_exit ; Y: exit with error +; +IE_find_phys: + call find_phys_pages ; find mappable physical pages + ; and page frame + test [msg_flag],KILLER_MSG ;Q: any killer messages + jz IE_alloc ; N: Go to find and allocate log. pages + jmp IE_exit ; Y: exit with error +; +; find and allocate logical emm pages +; +IE_alloc: + call AllocMem + test [msg_flag],KILLER_MSG ;Q: any killer messages? + jz IE_InitEMM ; N: init EMM + jmp IE_exit ; Y: exit +; +; init EMM data +; +IE_InitEMM: + + call EMM_Init + test [msg_flag],KILLER_MSG ;Q: any killer messages? + jz IE_InitVDM ; N: init VDM + jmp IE_exit ; Y: exit +; +; init VDM - GDT,IDT,TSS,Page Tables +; +IE_InitVDM: + call VDM_Init + test [msg_flag],KILLER_MSG ;Q: any killer messages? + jz IE_InitTAB ; N: init TABLES + jmp IE_exit ; Y: exit +; +; set up segment pointers to Tables & OEM table init +; +IE_InitTAB: + call InitTab + jnc IE_InitT_Good ;Q: any memory allocation error? + or [msg_flag],MEM_ERR_MSG ; Y: Some serious memory error +IE_InitT_Good: + test [msg_flag],KILLER_MSG ;Q: any killer messages? + jz IE_chkbase ; N: check base memory left + jmp IE_exit ; Y: exit +; +; Verify that we will have at least 64k of base memory after MEMM +; is loaded +; +IE_chkbase: + int 12h ; get base memory size + push ax ; save it + mov ax,[driver_end] ; get offset of end of MEMM resident + add ax,15 ; convert to paragraphs + shr ax,4 + add ax,[driver_end+2] ; add in segment of brk address + add ax,63 ; round up to kbytes (64 paras per K) + shr ax,6 ; AX = kbytes to end of MEMM resident + add ax,DOS3X_ADJ+64 ; add in dos 3.xx adjustment and 64k + pop dx ; get base memory back + cmp dx,ax ; q: do we have enough? + jae IE_setbrk ; y: continue + or [msg_flag],MEM_ERR_MSG ; n: set memory error + jmp IE_exit ; and exit + +; +; set driver break addr in Init Request Header +; +IE_setbrk: + mov bx,[bp+2] ; get entry DS from stack + mov es,bx + mov bx,[bp+10] ; ES:BX pts to req hdr + mov ax,[driver_end] ; get brk addr offset + mov ES:[bx.BRK_OFF],ax ; set it + mov ax,[driver_end+2] ; get brk addr segment + mov ES:[bx.BRK_SEG],ax ; set it +; +; check exit status of VDM/MEMM (now with lim 4.0) exit must be ON +; +; cmp [Auto_Mode],0 ;Q: exit in Auto mode ? +; je IE_chkOFF ; N: then continue +; mov [Active_Status],0 ; Y: exit in OFF state +;IE_chkOFF: +; cmp [Active_Status],0 ;Q: exit in real mode - OFF +; je IE_Exit ; Y: continue + +; Initialize DEBX_GSEL GDT Selector and Deb386 +; + push ds + push es + push ax + push bx + push cx + push si + push di + + push [IDT_Seg] + pop es ; ES:DI <-- IDT + push [GDT_Seg] + pop ds ; DS:SI <-- GDT + mov bx, DEBX_GSEL + and bl, SEL_LOW_MASK + mov word ptr [bx], 1800h ; Limit = 20M + mov word ptr [bx + 2], 0 + mov byte ptr [bx + 4], 0 ; Base = 0 + mov byte ptr [bx + 5], D_DATA0 ; Ring 0 Data + mov byte ptr [bx + 6], 80h ; Page Granularity + + mov ax, 4400h ; Initialize Deb386 + mov bx, DEBX_GSEL ; BIG selector for all addresses + mov cx, DEB1_GSEL ; start of 5 working Selector + xor si, si + xor di, di + int 68h + + pop di + pop si + pop cx + pop bx + pop ax + pop es + pop ds + + call FarGoVirtual ; N: go into virtual mode + +; +; exit - display status messages and set exit status +; +IE_exit: +; +; display signon message first +; + mov dx,offset LAST:InitMess + PRINT_MSG +; +; check for messages to display +; +IE_Install: + mov cx,MAX_MSG ; number of potential msgs + mov si,offset msg_tbl ; table of messages +m_loop: + test [msg_flag],01 ; q:is this one set? + jz m_inc_ptr ; n: increment table pointer + mov dx,cs:[si] ; y: display message + PRINT_MSG + cmp cx,KILL_MSG ; q: is this one a killer? + jbe m_inc_ptr ; n: continue + jmp IE_not_installed ; y: don't install +m_inc_ptr: + inc si ; increment msg table ptr + inc si + shr [msg_flag],1 ; look for next flag + loop m_loop +; + mov ax,[pool_size] ; size of EMM page pool in Kbytes + mov di,offset LAST:ISizeMess; store decimal size in ASCII here. + call b2asc10 ; convert to ASCII... +; + mov ax,[ext_size] +IFNDEF NOHIMEM + add ax,[hi_size] +endif + mov di,offset LAST:ExtSizeMess ; store decimal size of ext/hi alloc + ; here + call b2asc10 + + mov ax,[sys_size] + mov di,offset LAST:SysSizeMess ; system memory allocated + call b2asc10 +; + mov ax,[PF_Base] ; page frame base addr + shr ax,8 ; shift right to get significant digits + mov di,offset LAST:PFBAMess+1; where to put ascii base address +base_loop: + push ax ; save all digits + and ax,0fh ; get one digit + cmp ax,9 ; q: digit <=9 + jbe skip_dig_adj ; y: don't adjust + add ax,'A'-':' +skip_dig_adj: + add ax,'0' ; make it ascii + mov CS:[di],al ; store in message + dec di ; update pointer + pop ax ; get all digits back + ; shift right for next digit + shr ax,4 ; q: done? + jnz base_loop ; n: do another +; y: print it + mov dx,offset LAST:InstallMess + PRINT_MSG +; +; mov dx,offset LAST:AutoMess ; assume AUTO +; cmp [Auto_Mode],0 ;Q: auto mode ? +; jne print_mode ; Y: display message +; mov dx,offset LAST:InactiveMess ; N: assume OFF +; cmp [Active_Status],0 ; q: OFF specified? +; jz print_mode ; y +; mov dx,offset LAST:ActiveMess ; n +;print_mode: +; PRINT_MSG +; +; Ok, now we can patch int15h - must be careful not to install +; patch when Active_Status set, but not in virtual mode +; + pushf + cli ; clear ints + xor ax,ax + mov ds,ax ; DS -> 0:0 + ASSUME DS:ABS0 + les bx,dword ptr [i15_vector] ; DS:BX -> pts to old one + mov ax,offset R_CODE:i15_Entry + mov [i15_vector],ax ; set new ip + mov ax,seg R_CODE ; + mov [i15_vector+2],ax ; set new cs + mov ds,ax ; DS -> R_CODE + ASSUME DS:R_CODE + mov [i15_Old],bx ; save old IP + mov [i15_Old+2],es ; save old CS + popf ; restore IF + mov ax,seg DGROUP + mov ds,ax ; DS -> dgroup + ASSUME DS:DGROUP +; +; now patch int67 for EMM functions +; + pushf + cli ; clear ints + xor ax,ax + mov ds,ax ; DS -> 0:0 + ASSUME DS:ABS0 + mov ax,offset R_CODE:EMM_rEntry + mov [i67_vector],ax ; set new ip + mov ax,seg R_CODE ; + mov [i67_vector+2],ax ; set new cs + popf ; restore IF + mov ax,seg DGROUP + mov ds,ax ; DS -> dgroup + ASSUME DS:DGROUP +; +; all done with no errors +; + xor ax,ax ; NO errors +; +IE_leave: + pop es + pop ds + pop di + pop bp + pop dx + pop bx + ret +; +IE_not_installed: + call DeallocMem ; put back any memory we took + mov ax,ERROR ; error return + jmp IE_leave +; +Init_MEMM386 endp + +; +page +;****************************************************************************** +; +; parser - parse out MEMM parameters and set appropriate values +; for expanded memory size ([pool_size]), page frame base +; address ([PF_Base]) +; +; entry: es:di == config.sys command line parameters +; ds = DGROUP +; +; exit: [pool_size] = expanded memory size +; [PF_Base] = page frame base address +; [Active_Status] =flag for virtual/real mode exit +; [msg_flag] = appropriate messages to display +; +; used: none +; +;****************************************************************************** +; +parser proc near + push ax ; BP+16 + push bx ; BP+14 + push cx ; BP+12 + push dx ; BP+10 + push si ; BP+8 + push di ; BP+6 + push bp ; BP+4 + push ds ; BP+2 + push es ; BP+0 + mov bp,sp ; + cld ; make sure we go forward + xor ax,ax ; clear accumulator +; +; Skip past MEMM.EXE in command line +; +parm1_loop: ; find 1st parameter + mov al,es:[di] + cmp al,' ' ; q: find end of MEMM.exe? + jbe ploop1 ; y: start parsing + inc di ; n: try next one + jmp short parm1_loop +jmp_def: + jmp set_def +; +jmp_PF: + jmp chk_PF +; +;jmp_onf: +; jmp chk_onf +; +;jmp_auto: +; jmp chk_auto +; +jmp_Hx: + jmp chk_Hx +; +jmp_Xs: + jmp chk_Xs + +ploop1: + mov si,offset DGROUP:arg_str; ds:si = storage for argument + mov cx,max_arg_len ; maximum length of argument + call get_token_far ; get next token + or cx,cx ; q: anything there? + jz jmp_def ; n: go set default values + lodsb ; y: get 1st char + cmp al,'m' ; q: PF base address? + je jmp_PF ; maybe: go validate it + cmp al,'h' ; q: Himem enable /disable? + je jmp_Hx ; maybe: go validate it + cmp al,'x' ; q: Exclude segment parameter + je jmp_Xs ; maybe: go validate it +; cmp al,'o' ; q: ON/OFF? +; je jmp_onf ; maybe: go validate it +; cmp al,'a' ; q: AUTO? +; je jmp_auto ; maybe: go validate it + + cmp al,'0' ; q: is it a digit (size) + jb inv_parm ; n: invalid + cmp al,'9' ; q: is it a digit? + jbe chk_siz ; y: validate the size +inv_parm: + or [msg_flag],INV_PARM_MSG ; set invalid parameter flag + jmp short ploop1 ; continue +chk_siz: + mov bx,cx ; bx = number of digits + mov byte ptr [bx+si-1],' ' ; terminate string + mov cx,10 ; decimal multiplier + xor dx,dx ; clear upper 16 bits + xor bx,bx ; clear temporary accumulator + cmp [pool_size],0 ; q: have we already done this? + jz dig_loop ; n: continue + mov dx,1 ; y: skip all of this +dig_loop: + or dx,dx ; q: overflow? + jnz new_digit ; y: just skip rest of digits + sub al,'0' ; get ones value + xchg ax,bx ; swap accumulated value to ax + mul cx ; times 10 + add ax,bx ; add in ones value + adc dx,0 ; carry to dx + xchg ax,bx ; temporary value to bx +; +new_digit: + lodsb ; get new char into al + cmp al,'0' ; q: between 0 & 9? + jb dig_exit ; n: done + cmp al,'9' + ja dig_exit + jmp dig_loop ; y: process it +; +dig_exit: + cmp al,' ' ; q: any invalid digits? + jne ck_inv_parm ; y: invalid parameter + or dx,dx ; q: something wrong? + jz chk_siz1 ; n: not yet + cmp [pool_size],0 ; q: is this the second time for size? + jz siz_adj ; n: they just asked for too much +ck_inv_parm: + or [msg_flag],INV_PARM_MSG ; y: only let them do it once + jmp ploop1 ; continue +chk_siz1: + cmp bx,16 ;q: did they ask for too little? + jb siz_adj ; y: go adjust it + cmp bx,MAX_SIZE ;q: too much? + ja siz_adj ; y: adjust it + mov dx,0fh ; n: make sure it was a multiple of 16k + and dx,bx ;q: was it? + jz set_siz ; y: no problem + sub bx,dx ; n: drop it down + jmp siz_msg ; and give them the message +siz_adj: + mov bx,256 ; default value for size +siz_msg: + or [msg_flag],SIZE_ADJ_MSG ; size adjusted +set_siz: + mov [pool_size],bx ; save it + jmp ploop1 ; go check more parameters + + +; +; Check page frame base address +; +chk_PF: + cmp cx,2 ; q: 2 and only 2 chars in argument? + jne inv_prm ; n: error + lodsb ; get Mx specifier + cmp [PF_Base],0ffffh ; q: have they already specified this? + jnz inv_prm ; y: don't let them do it again + cmp al,'0' ; q: between 1 & 8? + jb inv_prm ; n: invalid + cmp al,'8' + ja inv_prm ; n: invalid + sub al,'0' ; make zero relative + xor ah,ah ; zero out hi bits + shl ax,1 ; make word offset + mov [PF_Base],ax ; store address + jmp ploop1 ; get next parameter + +; +; supporting use of Hi Ram. We are providing a command line option for this +; the parameter is specified as He for himem enable or Hd for Himem disable +; this parameter may be specified only once in a command line. Also +; +chk_Hx: +; cmp cx,2 ; q: 2 and only 2 chars in argument +; jne inv_prm ; n: error +; lodsb ; get Hx specifier +;; +; cmp [himem_use],0ffh ; has this already been specified +; jnz inv_parm +;; +; cmp al,'e' ; is user asking us to enable +; jne Hx$1 ; no, go to check enable +;; +; mov [himem_use],01h ; enable himem use +; jmp ploop1 +;Hx$1: +; cmp al,'d' +; jne inv_parm ; if neither d or e it is invalid +;; +; mov [himem_use],00h + jmp ploop1 + +; +inv_prm: + or [msg_flag],INV_PARM_MSG ; invalid + jmp ploop1 ; get next parameter +; +; +; check for exclusion of segments. this parameter is specfied thusly: +; +; X:nnnn-mmmm where nnnn is lo segment and mmmm is hi segment of range to +; be excluded from being mappable. +; +; more than one of these may be specified. +; +chk_Xs: + call handle_Xswitch + jc inv_parm + jmp ploop1 +; +; +; Check for ON/OFF +; +;chk_onf: +; lodsb ; get next char +; cmp [Active_Status],1 ; q: have they already specified this? +; jbe inv_prm ; y: ignore and set error flag +; cmp [Auto_Mode],1 ; n:q: have they specified auto_mode? +; je inv_prm ; y: ignore and set error flag +; cmp al,'n' ; q: on? +; jne onf_cont ; n: continue +; cmp cx,2 ; y: is that all there is? +; jne inv_prm ; n: error +; mov [Active_Status],1 ; y: set on +; mov [Auto_Mode],0 ; clear Auto mode +; jmp ploop1 ; get next parameter +;onf_cont: +; cmp al,'f' ; q: OF? +; jne inv_prm ; n: invalid +; lodsb ; y: get next char +; cmp al,'f' ; q: OFF? +; jne inv_prm ; n: invalid +; cmp cx,3 ; q: is that all there is? +; jne inv_prm ; n: error +; mov [Active_Status],0 ; y: set OFF +; mov [Auto_Mode],0 ; clear Auto mode +; jmp ploop1 ; get next parameter +; +; Check for AUTO +; +;chk_auto: +; cmp [Active_Status],1 ; q: have they already specified ON/OFF? +; jbe inv_prm ; y: ignore and set error flag +; cmp [Auto_Mode],1 ; n:q: have they specified auto_mode? +; je inv_prm ; y: ignore and set error flag +; cmp cx,AUTO_LEN ; n: q: parameter correct length ? +; jne inv_prm ; n: ignore and set error flag +; push es ; y: check for 'AUTO' +; push di +; dec si ; DS:SI pts to begin of arg +; mov di,offset LAST:AUTO_parm +; push cs +; pop es ; ES:DI pts to 'AUTO' +; cld +; repe cmpsb ;Q: do CX bytes compare ? +; pop di ; restore DI +; pop es ; restore ES +; jne inv_prm ; N: invalid parameter message +; mov [Auto_Mode],1 ; Y: set AUTO mode +; jmp ploop1 ; get next parameter +; +; Set default values for those items that were not specified +; +set_def: + + ; + ; default pool size if not defined is 256k + ; +set_pool_size: + cmp [pool_size],0 ; q: did they specify size? + jnz set_himem ; y: ok + mov [pool_size],256 ; n: set default + or [msg_flag],SIZE_ADJ_MSG ; display size adjusted + + ; + ; default of use of hi system ram is that it should not be used + ; +set_himem: +; cmp [himem_use],0ffh ; q:did they specify himem enb/dsb +; jnz parse_xit ; y: ok +; mov [himem_use],0 ; n: set default that it is not used + +parse_xit: ; restore registers and exit + pop es + pop ds + pop bp + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret +parser endp +; +; parser local data +; +;AUTO_parm db "auto" +;AUTO_LEN equ $-AUTO_parm + + +msg_tbl label word + dw offset LAST:Incorrect_PRT ; Incorrect Processor Type + dw offset LAST:Incorrect_DOS ; Incorrect Version of DOS + dw offset LAST:InsfMem ; Insufficient Memory + dw offset LAST:Already_Inst ; Already Installed + dw offset LAST:No_PF_Avail ; No Page Frame Space Avail +kill_end label word ; End of messages that kill driver + dw offset LAST:Adj_Size ; Pool Size Adjusted + dw offset LAST:InvPFBA ; Page Frame Base Addr Adjusted + dw offset LAST:InvMRA ; Map Register Adjusted + dw offset LAST:InvParm ; Invalid Parameter msg + dw offset LAST:PFWarning ; Page Frame warning message +MAX_MSG equ (this byte - msg_tbl)/2 ; # of messages to display +KILL_MSG equ (this byte - kill_end)/2; 1st four will abort driver +; + +page +;****************************************************************************** +; handle_Xswitch - processes the X switch to make some segments non-mappable ; +; ; +; entry: ds:di string with X switch parameters in form "X:nnnn-mmmm" ; +; cx is length of string +; ; +; exit: CY set if invalid parameter ; +; CY clear if parameter processed ; +; and non-mappable segments excluded ; +; ; +; uses: flags,ax,cx,si ; +; ; +; author: ISP 8/24/88 ; +; ; +;*****************************************************************************; +handle_XSwitch proc near +; + cmp cx,5 ; must have atleast 5 symbols + jb error_Xs ; +; + lodsb ; get the next letter ":" + sub cx,2 ; +; + cmp al,":" ; is it ":" + jne error_Xs ; if not it is a bad parameter +; + call htoi ; convert hex to integer + jcxz error_Xs ; if we have run out we have a bad parameter +; + mov bx,ax ; save in bx the start segment to be excluded +; + lodsb ; get the next letter + dec cx ; + jcxz error_Xs + cmp al,"-" ; is it the letter "-" + jnz error_Xs ; +; + call htoi ; convert hex to mappable + call exclude_segments + + clc ; set success and + ret ; return +error_Xs: + stc ; set error and + ret ; return +; +handle_XSwitch endp + +;-----------------------------------------------------------------------; +; htoi ; +; ; +; Converts a string to an integer. ; +; ; +; Arguments: ; +; DS:SI = string ; +; CX = length ; +; Returns: ; +; AX = integer ; +; DS:SI = remaining string ; +; CX = remaining length ; +; Alters: ; +; nothing ; +; Calls: ; +; nothing ; +; History: ; +; ; +; ISP (isp) 8/24/88 shifted from ps2emm srces ; +;-----------------------------------------------------------------------; + + +htoi proc near + push bx + xor ax,ax + mov bx,ax +htoi_loop: + jcxz htoi_done + +; get the next character + + mov bl,[si] + inc si + dec cx + +; see if it's a digit + + sub bl,'0' + cmp bl,9 + jbe have_hvalue + sub bl,'A'-'0' + cmp bl,'F'-'A' + jbe have_hvalue_but_10 + sub bl,'a'-'A' + cmp bl,'F'-'A' + ja htoi_not_digit +have_hvalue_but_10: + add bl,10 +have_hvalue: + +; shift and add + + shl ax,1 + shl ax,1 + shl ax,1 + shl ax,1 + add ax,bx + jmp htoi_loop +htoi_not_digit: + inc cx ; give back the character + dec si +htoi_done: + pop bx + ret +htoi endp + + + +page +;****************************************************************************** +; +; b2asc10 - converts binary to ascii decimal and store at CS:DI +; stores 5 ascii chars (decimal # is right justified and +; filled on left with blanks) +; +; entry: ax = binary number +; DS = DGROUP +; CS:di = place to store ascii chars. +; +; exit: ASCII decimal representation of number stored at DS:DI +; +; used: none +; +; stack: +; +;****************************************************************************** +; +b2asc10 proc near +; + push ax + push bx + push cx + push dx + push si + push di +; + mov si,8 ; pointer to base 10 table + xor bl,bl ; leading zeroes flag +; +; convert binary number to decimal ascii +; +b2_loop: + xor dx,dx ; clear word extension + mov cx,powr10[si] + div cx ; divide by power of 10 + or bl,bl + jnz b2_ascii +; + or ax,ax ; q: zero result? + jnz b2_ascii ; n: go convert to ascii +; + mov al,' ' ; y: go blank fill + jmp b2_make_strg ; +; +b2_ascii: + add al,'0' ; put into ascii format + mov bl,1 ; leading zeroes on +; +b2_make_strg: + mov CS:[di],al ; put ascii number into string + xchg ax,dx + inc di ; increment buffer string pointer + dec si ; decrement power of 10 pointer + dec si ; + jge b2_loop ; Q: Last digit? N: Jump if not +; + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret ; *** return *** +; +b2asc10 endp +; + +LAST ends ; End of segment +; + + end ; End of module + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/INITDEB.ASM b/v4.0/src/MEMM/MEMM/INITDEB.ASM new file mode 100644 index 0000000..76db0dc --- /dev/null +++ b/v4.0/src/MEMM/MEMM/INITDEB.ASM @@ -0,0 +1,180 @@ + + +page 58,132 +;****************************************************************************** + title InitDeb - initialize debugger +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: InitDeb - initialize debugger +; +; Version: 0.04 +; +; Date: June 16,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/16/86 Original from VDM MAIN.ASM module +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/06/86 0.04 Changed assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; +; This routine is linked in when linking with the kernel debugger. +; InitDeb calls the debugger initialization routine. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p +;****************************************************************************** +; P U B L I C S +;****************************************************************************** + + public InitDeb + +;****************************************************************************** +; D E F I N E S +;****************************************************************************** + include VDMseg.inc + include VDMsel.inc + +FALSE equ 0 +TRUE equ not FALSE +CR equ 0dh +LF equ 0ah + +MASTER_IMR equ 21h ; mask port for master 8259 + +; +; Definition of the packet used in debug initialization. A pointer to +; this structure is passed to Debug_Entry. +; +DebugInit struc + CSseg dw ? ;Real mode code segment + DSseg dw ? ;Real mode data segment + CSsel dw ? ;Prot mode code selector + DSsel dw ? ;Prot mode data selector + SpareSel1 dw ? ;Prot mode alias selector 1 + SpareSel2 dw ? ;Prot mode alias selector 2 + GDTalias dw ? ;Prot mode GDT r/w alias + ProtIDTaddr dq ? ;Prot mode IDT base & limit + RealIDTaddr dq ? ;Real mode IDT base & limit + BrkFlag db ? ;TRUE if break to debugger + ComFlag db ? ;TRUE if com1, FALSE if com2 +DebugInit ends + + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +ifndef NoBugMode +dcode segment +extrn _Debug_Entry:far ; (debinit.asm) +dcode ends +endif + +_DATA SEGMENT + +extrn GDT_Seg:word + +_DATA ENDS + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N S +;****************************************************************************** + +_DATA SEGMENT + +InitData DebugInit <> + +_DATA ENDS + +; +; code +; +LAST SEGMENT + + assume cs:LAST, ds:DGROUP, es:DGROUP + +;****************************************************************************** +; InitDeb - initialize kernel debugger +; +; +; ENTRY: Real Mode +; DS = DGROUP +; AL = 00h => dont't break on debug init +; AL = FFh => break on debug init +; +; EXIT: Real Mode +; Kernel debugger initialized +; +; USED: none +; +;****************************************************************************** +InitDeb proc near +; +ifndef NoBugMode + pusha + push ds + push es +; + push ds + pop es ; ES = data +; + mov di, offset DGROUP:InitData + + mov bx, dcode + mov [di].CSseg, bx + mov bx, ddata + mov [di].DSseg, bx + mov [di].CSsel, DEBC_GSEL + mov [di].DSsel, DEBD_GSEL + mov [di].SpareSel1, DEBW1_GSEL + mov [di].SpareSel2, DEBW2_GSEL + mov [di].GDTalias, GDTD_GSEL + mov [di].BrkFlag, al ; ? break on entry ? + mov [di].ComFlag, FALSE ; com2 + + sidt [di].RealIDTaddr + + push ds + push di + mov ax, [GDT_Seg] + mov ds, ax + + lgdt qword ptr ds:[GDTD_GSEL] + + mov si, IDTD_GSEL + mov cx, 6 + lea di, [di].ProtIDTaddr + cld + rep movsb + pop di + pop ds + + call _Debug_Entry +; +; and return +; + pop es + pop ds + popa +endif + ret +InitDeb endp + + +LAST ends + + END diff --git a/v4.0/src/MEMM/MEMM/INITEPG.ASM b/v4.0/src/MEMM/MEMM/INITEPG.ASM new file mode 100644 index 0000000..7129b17 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/INITEPG.ASM @@ -0,0 +1,377 @@ + + +page 58,132 +;****************************************************************************** + title InitEPage - initialize EMM Page pointers +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: InitEPage - initialize EMM Page pointers +; +; Version: 0.05 +; +; Date: June 4,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/04/86 Original +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/06/86 0.04 _pft386 changed to a ptr +; 07/06/86 0.04 fixed hdma_exit label to edma_exit +; 07/06/86 0.04 changed assume to DGROUP +; 07/09/86 0.05 added to FindDMA routine +; +;****************************************************************************** +; +; Functional Description: +; +; This module initializes the array of pointers to the EMM Pages used +; by the expanded memory manager code. Specifically, this module initializes +; the array EMM_PTE. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public InitEPage + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + include page.inc + include instr386.inc + include emmdef.inc +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; + +LAST segment + +ifndef NOHIMEM +extrn Hi_Mem_Size:near +endif + +extrn mappable_segs:byte + +LAST ends + + +ABS0 segment at 0000h +ABS0 ends + + +_DATA segment + +extrn DMA_Pages:word ; DMA EMM pages buffer +extrn DMA_PAGE_COUNT:word ; number of DMA pages + +extrn xbase_addr_l:word ; 24 bit address of beginning of extended mem +extrn xbase_addr_h:byte ; pool of EMM pages. +extrn ext_size:word ; size of extended memory in kbytes +extrn sys_size:word ; size of system memory in kbytes + +extrn _pft386:word ; ptr to dword array of Page Table entries + +_DATA ends + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +_DATA segment + +ifndef NOHIMEM +DMA_hi_begin dw 0 ; EMM page # for begin of DMA area in hi mem +DMA_hi_cnt dw 0 ; # of contiguous EMM pages in hi mem DMA area +endif + +DMA_ext_begin dw 0 ; EMM page # for begin of DMA area in ext mem +DMA_ext_cnt dw 0 ; # of contiguous EMM pages in ext mem DMA area + +; +; FindDMA variables +; +crossed db 0 ; flag => crossed 1st 64k bndry +b_start dw 0 ; 1st EMM page before 1st 64k bndry +b_cnt dw 0 ; # of EMM pages before 1st 64k bndry +a_start dw 0 ; 1st EMM page after 1st 64k bndry +a_cnt dw 0 ; # of EMM pages after 1st 64k bndry + + +_DATA ends +; +;------------------------------------------------------------------------------ +LAST segment + assume cs:LAST, ds:DGROUP, es:DGROUP, ss:DGROUP + page +;****************************************************************************** +; InitEPage - init EMM_PTE - array of pointers for EMM pages. +; +; ENTRY: Real Mode +; DGROUP:[xbase_addr_l] = 24 bit address of beginning of extended mem +; DGROUP:[xbase_addr_h] pool of EMM pages. +; DGROUP:[ext_size] = size of extended memory buffer in kbytes +; +; EXIT: Real Mode +; DGROUP:[DMA_Pages] = initialized to point to up to 8 physically +; contiguous EMM pages in high memory. +; DGROUP:[_pft386] = pts to array of ptrs for EMM Pages +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +InitEPage proc near +; + PUSH_EAX + push bx + push cx + push dx + push si + push di + push ds + push es +; + cld +; + mov ax,seg DGROUP + mov ds,ax + mov es,ax + mov di,[_pft386] ; ES:DI points to begin of table +; + mov bx,0 ; BX = current EMM page # +; +; set system memory pointers first +; + mov cx,[sys_size] ; get size of system memory in kb + shr cx,4 ; convert to number of pages + jcxz fin_sys + mov eax,0000h*16 ; address of first system page + xor si,si ; index into mappable page array +; +; store in pft386 array +; +SEP_hloop: + cmp cs:mappable_segs[si],PAGE_MAPPABLE + jne not_this_page +; + stosd + inc bx ; next emm page + dec cx + jcxz fin_sys ; found all pages +not_this_page: + inc si + add eax,4000h ; point to next 16k page + jmp SEP_hloop ; +fin_sys: +; +ifndef NOHIMEM +; +; set high memory pointers next +; + call Hi_Mem_Size ; CX = kbytes of high mem, + ; EAX = pointer to high mem + ;Q: any hi memory pages ? CX = pg cnt + jz IEP_ext ; N: set up ext mem pointers + ; Y: set high memory pointers +; +; check for contiguous EMM pages +; + push bx ; first hi mem EMM page # + push cx ; save # of hi mem EMM pages + call FindDMA ; find the DMA pages for hi mem + mov [DMA_hi_begin],bx ; save begin EMM page # + mov [DMA_hi_cnt],cx ; save cnt + pop cx ; restore # of hi mem EMM pages + pop bx ; restore EMM page# for 1st of hi mem +; +; set entries in _pft386 +; +IEP_hloop: + db 66h + stosw ; set this table entry + db 66h + add ax,4000h ; ADD EAX,4000h + dw 0000h ; EAX = addr of next EMM page + inc bx ; increment EMM page # + loop IEP_hloop ; set all high memory entries + +endif ; NOHIMEM + +; +; set extended memory entries +; +IEP_ext: + mov cx,[ext_size] ; CX = kbytes of ext memory + shr cx,4 ;Q: any ext memory pages ? CX = pg cnt + jz IEP_Dpages ; N: all done - leave + db 66h ; Y: set ext memory pointers + mov ax,[xbase_addr_l] ; get pointer to ext memory pool + db 66h + and ax,0FFFFh ; AND EAX,00FFFFFFh + dw 00FFh ; clear highest nibble +; +; check for contiguous EMM pages +; + push bx ; first ext mem EMM page # + push cx ; save # of ext mem EMM pages + call FindDMA ; find the DMA pages for ext mem + mov [DMA_ext_begin],bx ; save begin EMM page # + mov [DMA_ext_cnt],cx ; save cnt + pop cx ; restore # of ext mem EMM pages + pop bx ; restore EMM page# for 1st of ext mem +; +; set entries in _pft386 +; +IEP_xloop: + db 66h + stosw ; set this table entry + db 66h + add ax,4000h ; ADD EAX,4000h + dw 0000h ; EAX = addr of next EMM page + inc bx ; increment EMM page # + loop IEP_xloop ; set all ext memory entries +; +; +; set up DMA Pages +; +IEP_Dpages: +ifndef NOHIMEM + mov ax,[DMA_hi_begin] ; SI = beginning hi mem DMA page + mov cx,[DMA_hi_cnt] ; CX = # of hi mem DMA pages + cmp cx,[DMA_ext_cnt] ;Q: more hi DMA pages ? + jae IEP_Dset ; Y: use hi mem DMA pages +endif + mov cx,[DMA_ext_cnt] ; N: use ext mem pages + mov ax,[DMA_ext_begin] +IEP_Dset: + + mov DMA_Page_Count,cx + mov di,offset DGROUP:DMA_Pages ; ES:DI ->dest array + cld +DMA_Pg_St: + stosw ; store index for dma page + inc ax ; + loop DMA_Pg_St ; +; +; all done +; + pop es + pop ds + pop di + pop si + pop dx + pop cx + pop bx + POP_EAX + ret +; +InitEPage endp +; + +;****************************************************************************** +; FindDMA - find contiguous DMA pages +; +; ENTRY: Real Mode +; EAX = 24 bits of beginning address of EMM memory pool +; BX = first EMM page # +; CX = # of EMM pages in this pool +; +; EXIT: Real Mode +; BX = EMM page# of first DMA page +; CX = # of DMA pages +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +FindDMA proc near +; + push eax + +; +; initialise the variables needed for this calculation +; + mov [b_start],bx + mov [a_start],bx + mov [crossed],0 + mov [a_cnt],0 + mov [b_cnt],0 + + jcxz fdp_exit ; if no pages to check exit ... +; +; convert physical address in eax (which is assumed to be aligned on 4k bdry) +; to page # (in 4k physical pages) modulo 32. This is to find the page # in +; the current 128k block +; + shr eax,12 ; physical_address >> 4*1024 + and ax,01fh ; modulo 32, also sets Z flag if on 128k + ; bdry. So Q: On 128K bdry? + jnz fdp_loop ; N: continue as normal + mov [crossed],1 ; Y: set flag + +fdp_loop: + add ax,04h ;Q: add 16k bytes, did it cross 128k ? + test ax,NOT 01fh ; if into next 128k it will go into next + ; bit + je fdp_no_cross ; N: continue + cmp [crossed],0 ; Y:Q: have we crossed it before ? + je fdp_cross1 ; N: update counts + and ax,01fh ; Y:Q: equal to 128k bndry ? + jnz fdp_exit ; N: then leave + inc [a_cnt] ; Y: update last cnt + jmp fdp_exit ; and leave + +fdp_cross1: ; first crossing of 128k bndry + mov [crossed],1 ; set crossed flag. + mov [a_start],bx ; start with ... + inc [a_start] ; next page. + and ax,01fh ;Q: equal to 128k bndry ? + jnz fdp_next ; N: next page + inc [b_cnt] ; Y: include page in before pages + jmp fdp_next ; and go to next page + +fdp_no_cross: + cmp [crossed],0 ;Q: have we crossed first 64k bndry ? + jne fdp_n_c ; Y: update it's count + inc [b_cnt] ; N: update before count + jmp fdp_next +fdp_n_c: + inc [a_cnt] ; update after count +fdp_next: + inc bx ; next page # + loop fdp_loop ; and continue +; +fdp_exit: + mov bx,[b_start] ; BX = first page before + mov cx,[b_cnt] ; CX = cnt of pages before + cmp cx,[a_cnt] ;Q: more before than after ? + jae fdp_ret ; Y: return pages before + mov bx,[a_start] ; N: return pages after + mov cx,[a_cnt] ; +fdp_ret: + pop eax ; restore EAX + ret +; +FindDMA endp + +LAST ends ; end of segment +; + end ; end of module diff --git a/v4.0/src/MEMM/MEMM/INITTAB.ASM b/v4.0/src/MEMM/MEMM/INITTAB.ASM new file mode 100644 index 0000000..c37b78e --- /dev/null +++ b/v4.0/src/MEMM/MEMM/INITTAB.ASM @@ -0,0 +1,632 @@ + + +page 58,132 +;****************************************************************************** + title InitTab - OEM init routines to init tables +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: InitTab +; +; Version: 0.05 +; +; Date: June 4,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/04/86 Original +; 06/21/86 0.02 Added cld +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/05/86 0.04 Added NOHIMEM ifdef and added code to +; move _TEXT segment to high mem +; 07/06/86 0.04 changed assume to DGROUP +; 07/06/86 0.04 added ring0 stack move +; 07/10/86 0.05 removed CODE_GSEL reset +; 07/10/86 0.05 PageT_Seg and PageD_Seg +; +;****************************************************************************** +; +; Functional Description: +; +; This module is called after the system has been set up in a viable +; state to start executing MEMM. This routine provides a "hook" where +; the tables (GDT,IDT,TSS, & PageTables, etc) can be modified. This routine +; must set the variables which hold the 32 bit address for each of the +; VDM tables. This routine also sets up the EXTRA1_GSEL to point to the +; Diagnostics byte segment. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public InitTab + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +OEM_MEM_HI equ 80c0h ; Upper 16 bits of high mem physical adr + + include VDMseg.inc + include VDMsel.inc + include desc.inc + include page.inc + include instr386.inc + include oemdep.inc +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; + +GDT segment + extrn GDTLEN:abs +GDT ends + +IDT segment + extrn IDTLEN:abs +IDT ends + +TSS segment + extrn TSSLEN:abs +TSS ends + +PAGESEG segment + extrn P_TABLE_CNT:abs +PAGESEG ends + + +_DATA segment + extrn TEXT_Seg:word ; segment for TEXT + extrn STACK_Seg:word ; segment for STACK + extrn GDT_Seg:word ; segment for GDT + extrn IDT_Seg:word ; segment for IDT + extrn TSS_Seg:word ; segment for TSS + extrn PageD_Seg:word ; segment for page dir + extrn PageT_Seg:word ; segment for page table + extrn Page_Dir:word ; 32 bit address for Page directory + extrn driver_end:dword ; ending address for MEMM.EXE + extrn _emm_brk:word ; break address for EMM data + +_DATA ends + +LAST segment +ifndef NOHIMEM + extrn HiSysAlloc:near ; allocate high system memory + extrn UnLockROM:near + extrn LockROM:near +endif + extrn SegTo24:near + extrn SetSegDesc:near + extrn SetPageEntry:near + extrn moveb:near + extrn get_buffer:near + +LAST ends + +_TEXT segment + extrn Real_Seg:word ; fixup for _TEXT in RetReal (retreal.asm) +_TEXT ends + +R_CODE segment + extrn EFunTab:word ; table of ELIM functions + extrn EFUN_CNT:abs ; # of entries in table + extrn EMM_rEfix:near ; far call to EMM function dispatcher in _TEXT +R_CODE ends + + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +;------------------------------------------------------------------------------ +LAST segment + assume cs:LAST, ds:DGROUP, es:DGROUP, ss:DGROUP + page +;****************************************************************************** +; InitTab - init tables & 32 bit address +; +; ENTRY: Real Mode +; GDT = current segment for GDT +; IDT = current segment for IDT +; TSS = current segment for TSS +; _TEXT = current segment for _TEXT +; STACK = current segment for STACK +; DGROUP:[PageD_Seg] = current segment portion of page directory +; DGROUP:[PageT_Seg] = current segment portion of page tables +; DGROUP:[Page_Dir] = current 32 bit address for page directory +; IDTLEN:abs = length of IDT +; TSSLEN:abs = length of TSS +; P_TABLE_CNT:abs = # of page TABLES +; _TEXT:[Real_Seg] = fixup location for _TEXT in RetReal +; R_CODE:[EFunTab] = table of ELIM functions +; R_CODE:EFUN_CNT = # of entries in table +; R_CODE:[EMM_rEfix] = far call to EMM function dispatcher in _TEXT +; +; EXIT: Real Mode +; DGROUP:[TEXT_Seg] = current segment for TEXT +; DGROUP:[STACK_Seg] = current segment for STACK +; DGROUP:[GDT_Seg] = current segment for GDT +; DGROUP:[IDT_Seg] = current segment for IDT +; DGROUP:[TSS_Seg] = current segment for TSS +; DGROUP:[PageD_Seg] = current segment portion of page directory +; DGROUP:[PageT_Seg] = current segment portion of page tables +; DGROUP:[Page_Dir] = current 32 bit address for page directory +; DGROUP:[driver_end] = end of MEMM.EXE device driver +; GDT:[IDTD_GSEL] = current descriptor for IDT +; GDT:[TSS_GSEL] = current descriptor for TSS +; GDT:[TSSD_GSEL] = current descriptor for TSS +; GDT:[PAGET_GSEL] = current descriptor for Page TABLES +; +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +InitTab proc near +; +ifndef NOHIMEM + + PUSH_EAX + push di + push ds + push es + pushf + cli ; turn off ints + cld ; strings foward +; + mov ax,seg DGROUP + mov ds,ax +; +; set up GDT entry for the diagnostics segment +; + mov ax, seg GDT ; GDT not moved yet ! + mov es,ax + + xor dx,dx + mov al,00h ; only low 24 bits of address here ! + mov cx,0 ; 64k long + mov ah,D_DATA0 ; data segment + mov bx,OEM0_GSEL + call SetSegDesc ; Set up GDT alias descriptor + mov ES:[bx.BASE_XHI],01h ; set high 8 bits of address + +; +;------------------------------------------------------------------------------ +; Move Tables to HIGH SYSTEM memory +; The high system memory is mapped to FE0000h - FEFFFFh +; AND 0E0000h-0EFFFFh. The following code copies data to the E0000h +; range +;------------------------------------------------------------------------------ +; + +; +;------------------------------------------------------------------------------ +; move PAGE DIR/TABLES up to high memory +;------------------------------------------------------------------------------ +; + mov ax,P_TABLE_CNT ; AX = # of page tables + inc ax ; include page directory + mov cx,ax ; CX=AX = # of pages for page table seg + call HiSysAlloc ;Q: enough room in high sys mem ? + jnc IT_move_pt ; Y: move page dir/tables to hi sys mem + inc ax ; N: Q: is error not enough room? + jnz To_IT_Exit ; Y: just go ahead and exit + popf + stc ; N: return CF = 1(mem alloc error) + jmp IT_Quit +To_IT_Exit: + jmp IT_Exit ; N: then nothing is moved up +IT_move_pt: ; + call UnLockROM ;turn off write protect + shl ax,8 ; + add ax,0E000h ; AX = segment for sys mem block + mov es,ax ; ES -> sys mem block + xor di,di ; ES:DI -> sys mem block + mov ax,[PageD_Seg] ; + mov ds,ax ; DS -> page dir/tables + xor si,si ; DS:SI -> page dir/tables + shl cx,10 ; CX = # of dwords in page tables + cld + OP32 + rep movsw ; mov cx dwords into hi sys mem +; + mov ax,seg DGROUP + mov ds,ax ; DS = DATA +; +; reset break address for driver +; + mov word ptr [driver_end],0 + mov ax,[PageD_Seg] + mov word ptr [driver_end+2],ax + +; +; reset page dir/table pointers + XOR_EAX_EAX ; clear eax + mov ax,es ; + mov [PageD_Seg],ax ; reset segment for page dir + add ax,P_SIZE/10h ; ax = segment page table + mov [PageT_Seg],ax ; rest it + + mov ax,es ; get page dir seg again + OP32 + shl ax,4 ; shl EAX,4 => EAX = 32 bit address + OP32 + mov [Page_Dir],ax ; store 32 bit addr of page dir +; +; reset page directory entries +; + mov ax,word ptr [Page_Dir] ; DX,AX = 32 bit addr of Page Directory + mov dx,word ptr [Page_Dir+2] ; save it +; +; get addr of Page Table for Page Directory entry +; + add ax,1000h ; add page + adc dx,0h ; carry it => DX,AX = addr of page table +; +; DX,AX = addr of first page table +; + xor di,di ; ES:[DI] -> 1st entry in page dir + mov bh,0 + mov bl,P_AVAIL ; make table available to all + mov cx,P_TABLE_CNT ; set entries in page table directory + ; for existing page tables. +IT_pdir: + call SetPageEntry ; set entry for first page table +; +; ES:[DI] pts to next entry in page directory + add ax,1000h + adc dx,0 ; DX,AX = addr of next page table + loop IT_pdir ; set next entry in dir +; +; reset PAGET_GSEL descriptor +; + mov ax,seg GDT ; GDT has not yet moved!!! + mov es,ax ; ES pts to GDT + + mov ax,[PageT_Seg] ; segment for page tables + call SegTo24 + mov cx,0 ; enough room for tables + mov ah,D_DATA0 + mov bx,PAGET_GSEL + call SetSegDesc ; set up page table descriptor +; +; now set CR3 in the TSS - to reflect new Page DIR position +; + mov ax,seg TSS ; TSS not moved yet !!! + mov es,ax ; ES -> TSS + xor di,di ; ES:DI -> TSS + + db 66h + mov ax,[Page_Dir] ; EAX = page dir 32 bit addr + db 66h + mov word ptr ES:[di.TSS386_CR3],ax ; mov EAX into CR3 spot in TSS +; +;------------------------------------------------------------------------------ +; move _TEXT, GDT,IDT, & TSS up to high system memory +; **** this code depends on the order of the _TEXT, GDT, IDT, & TSS +; segments when linked. They should be in the order +; _TEXT, GDT, IDT, then TSS. +;------------------------------------------------------------------------------ +; + mov ax,seg TSS ; compute # of paras from begin of _TEXT + sub ax,seg _TEXT ; to begin of TSS + shl ax,4 ; convert it to bytes + add ax,TSSLEN ; and add in length of TSS + ; AX=length of _TEXT,GDT,IDT, & TSS segs + add ax,P_SIZE-1 ; round up to nearest page boundary + shr ax,12 ; AX = # of 4k pages for these tables + mov cx,ax ; CX=AX = # of pages for these tables + call HiSysAlloc ;Q: enough room in high sys mem ? + jnc IT_move_tables ; Y: move page dir/tables to hi sys mem + call LockROM ; N: move nothing. write protect ROM + jmp IT_Exit ; +IT_move_tables: + call UnLockROM ; turn off write protect + shl ax,8 ; AX = # of paras already allocated + ; in high memory + add ax,0E000h ; AX = segment for sys mem block + mov es,ax ; ES -> sys mem block + xor di,di ; ES:DI -> sys mem block + + mov ax,seg _TEXT ; start with _TEXT + mov ds,ax ; DS -> _TEXT + xor si,si ; DS:SI -> _TEXT + shl cx,10 ; CX=# of dwords for _TEXT,GDT,IDT,&TSS + cld + OP32 + rep movsw ; mov _TEXT,GDT,IDT,&TSS into hi sys mem + +; +; now reset pointers to _TEXT, GDT, IDT, & TSS + mov ax,seg DGROUP + mov ds,ax ; DS = DATA + + mov ax,es ; AX = segment for new _TEXT location + mov [TEXT_Seg],ax ; set new _TEXT segment + + mov bx,seg GDT + sub bx,seg _TEXT ; bx = offset from _TEXT to GDT + add ax,bx ; (don't worry, won't cross Linear 64k) + mov [GDT_Seg],ax ; set new GDT segment + + mov bx,seg IDT + sub bx,seg GDT ; bx = offset from GDT to IDT + add ax,bx ; (don't worry, won't cross Linear 64k) + mov [IDT_Seg],ax ; set new IDT segment + + mov bx,seg TSS + sub bx,seg IDT ; bx = offset from IDT to TSS + add ax,bx ; (don't worry, won't cross Linear 64k) + mov [TSS_Seg],ax ; set new TSS segment +; +; reset descriptors for _TEXT, GDT, IDT, & TSS +; + mov ax,[GDT_Seg] ; GDT has MOVED !!! + mov es,ax ; ES pts to GDT + + mov ax,[TEXT_Seg] ; _TEXT segment + call SegTo24 + mov cx,0 + mov ah,D_CODE0 + mov bx,VDMC_GSEL + call SetSegDesc ; Set up VDM code descriptor - VDMC + + mov ax,[TEXT_Seg] ; _TEXT segment + call SegTo24 + mov cx,0 + mov ah,D_DATA0 + mov bx,VDMCA_GSEL + call SetSegDesc ; Set up VDM code alias descriptor + + mov ax,[GDT_Seg] ; GDT segment + call SegTo24 + mov cx,GDTLEN + mov ah,D_DATA0 + mov bx,GDTD_GSEL + call SetSegDesc ; Set up GDT alias descriptor + + mov ax,[IDT_Seg] ; IDT segment + call SegTo24 + mov cx,IDTLEN + mov ah,D_DATA0 + mov bx,IDTD_GSEL + call SetSegDesc ; Set up IDT alias descriptor + + mov ax,[TSS_Seg] ; segment of TSS + call SegTo24 + mov cx,TSSLEN + mov ah,D_386TSS0 + mov bx,TSS_GSEL + call SetSegDesc ; Set up TSS descriptor + + mov ah,D_DATA0 + mov bx,TSSD_GSEL + call SetSegDesc ; Set up TSS alias descriptor + +; +; fixup new RING 0 stack location +; + mov ax,[_emm_brk] ; get EMM break address + add ax,15 ; round up to next paragraph + shr ax,4 + add ax,seg _DATA ; AX = new seg address for STACK + mov [STACK_seg],ax ; save it + + call SegTo24 + mov cx,offset STACK0_SIZE ; length of stack + mov ah,D_DATA0 + mov bx,VDMS_GSEL + call SetSegDesc ; Set up STACK segment GDT entry + +; +; fixup far call / far jump references to _TEXT +; + +; far call pointers in ELIM function table + mov ax,seg R_CODE + mov es,ax ; ES -> R_CODE + mov di,offset R_CODE:EFunTab+2 ; ES:DI -> 1st seg in func tab + mov cx,EFUN_CNT ; CX = # of dword entries + mov ax,[TEXT_Seg] +IT_Tloop: + stosw ; store new TEXT seg + inc di + inc di ; point to next seg in table + loop IT_Tloop + +; ELIM_rEntry far call + mov di,offset R_CODE:EMM_rEfix ; point to far call + mov ES:[di+3],ax ; set seg portion of call + +; Far jump in return to real code + mov es,ax ; ES -> new TEXT seg + mov di,offset _TEXT:Real_Seg ; ES:DI -> seg of far jmp + mov ES:[di],ax ; fix it + +; +; reset break address for driver - throw away _TEXT seg and all after it +; + mov word ptr [driver_end],10h ; just in case + mov ax,[STACK_Seg] ; begin of new stack location + add ax,STACK0_SIZE/10h ; add in size of stack + mov word ptr [driver_end+2],ax ; set break seg to end of stack + +; +; OK, now lock high system RAM +; + call LockROM +; +IT_exit: + popf + clc ; No error in memory allocation attempt +IT_quit: + pop es + pop ds + pop di + POP_EAX +else + + push es + push di + push eax + push dx + push cx + push bx +; +; try to move the pageseg up +; + ; + ; segment to be moved up + ; + mov ax, [PageD_Seg] + mov es,ax + ; + ; its length + ; + mov ax,seg LAST + sub ax,seg PAGESEG + shl ax,4 + mov cx,ax + ; + ; we need to allocate enough to have a page aligned page directory. so + ; increase this by 4k + push cx + add cx,4*1024 + ; + ; allocate a block of memory for this + + call get_buffer + pop cx + jc no_mem + ; + ; dx:ax is new address of page directory, adjust this to be page aligned + ; + add ax,4*1024 + adc dx,0 + and ax,0F000h + ; + push ax + push dx + push cx + ; + add ax,1000h + adc dx,0h + ; + ; set the entries in the page directory for these + ; + xor di,di ; es:di points to first page_dir entry + mov bh,0 + mov bl, P_AVAIL + mov cx,P_TABLE_CNT +set_entries: + call SetPageEntry + ; + ; es:di points to next entry in page directory + ; + add ax,1000h + adc dx,0 ; next page table + loop set_entries + ; + ; now we can move the page directory and tables up into extended + ; + pop cx + pop dx + pop ax + ; + xor di,di ; es:di is now the beginning, cx count of + ; number of bytes in segment and dx:ax area + ; where it is to be moved + call moveb ; move the data + jnz move_error ; there was an error in moving. the page + ; table entries need to be restored to the + ; lo memory stuff + ; + ; move succeded, fix page directory address and driver_end + ; + mov word ptr [Page_Dir],ax ; DX,AX = 32 bit addr of Page Directory + mov word ptr [Page_Dir+2],dx ; save it +; +; reset PAGET_GSEL descriptor +; + mov cx,seg GDT ; GDT has not yet moved!!! + mov es,cx ; ES pts to GDT + + add ax,1000h + adc dx,0 + xchg ax,dx ; for setsegdesc in opposite + ; al:dx + + mov cx,0 ; enough room for tables + mov ah,D_DATA0 + mov bx,PAGET_GSEL + call SetSegDesc ; set up page table descriptor + ; + ; if we succeed in shifting the page tables up the ground is clear for us + ; to shrink the driver even more to the point where the variable emm data + ; structures end. + ; + mov ax,[_emm_brk] ; get EMM break address + add ax,15 ; round up to next paragraph + shr ax,4 + add ax,seg DGROUP ; AX = end address for driver + mov word ptr [driver_end],10h ; just in case, para offset + mov word ptr [driver_end+2],ax ; segment + + +no_mem: + pop bx + pop cx + pop dx + pop eax + pop di + pop es + clc + jmp end_inittab + +move_error: + ; the address of page table in lo mem + ; + mov ax,[PageT_Seg] + mov cx,4 + xor dx,dx + mul cx + ; + ; set the entries in the page directory for these + ; + xor di,di ; es:di points to first page_dir entry + mov bh,0 + mov bl, P_AVAIL + mov cx,P_TABLE_CNT +restore_entries: + call SetPageEntry + ; + ; es:di points to next entry in page directory + ; + add ax,1000h + adc dx,0 ; next page table + loop restore_entries + ; + jmp no_mem +endif +end_inittab: + ret +; +InitTab endp +; +LAST ends ; end of segment +; + end ; end of module diff --git a/v4.0/src/MEMM/MEMM/INSTR386.INC b/v4.0/src/MEMM/MEMM/INSTR386.INC new file mode 100644 index 0000000..490435a --- /dev/null +++ b/v4.0/src/MEMM/MEMM/INSTR386.INC @@ -0,0 +1,563 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: INSTR386 - 386 Instruction Macro Declaration file +; +; Version: 0.03 +; +; Date: May 11, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 05/11/86 Original +; 06/01/86 Added operand/address size overide defines +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/01/86 0.03 Added 32 arithmetic defines +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +;*** OP32_IRET - 32 bit mode iret +OP32_IRET macro + db 66h + iret + endm + +;*** OP32 - instruction prefix to invert sense of operand size attribute + +OP32 macro + db 66h + endm + + +;*** EA32 - instruction prefix to invert sense of effective addr attribute + +EA32 macro + db 67h + endm + + +;*** FS and GS overides +FSOVER macro + db 64h + endm +GSOVER macro + db 65h + endm + +; *** General Register 32 bit moves *** + +MOV_EBX_EAX macro + db 66h + mov bx, ax + endm + +MOV_EAX_EBX macro + db 66h + mov ax, bx + endm + +MOV_ECX_EAX macro + db 66h + mov cx, ax + endm + +MOV_EAX_ECX macro + db 66h + mov ax, cx + endm + +MOV_EDX_EAX macro + db 66h + mov dx, ax + endm + +MOV_EAX_EDX macro + db 66h + mov ax, dx + endm + +MOV_EDI_EAX macro + db 66h + mov di, ax + endm + +MOV_EAX_EDI macro + db 66h + mov ax, di + endm + +MOV_ESI_EAX macro + db 66h + mov si, ax + endm + +MOV_EAX_ESI macro + db 66h + mov ax, si + endm + +MOV_EBP_EAX macro + db 66h + mov bp, ax + endm + +MOV_EAX_EBP macro + db 66h + mov ax, bp + endm + +MOV_ESP_EAX macro + db 66h + mov sp, ax + endm + +MOV_EAX_ESP macro + db 66h + mov ax, sp + endm + +; *** Special Register/EAX 32 bit moves *** + +MOV_CR0_EAX macro + db 0Fh,22h,0C0h + endm + +MOV_CR0_EBX macro + db 0Fh,22h,0C3h + endm + +MOV_CR0_ECX macro + db 0Fh,22h,0C1h + endm + +MOV_CR0_EDX macro + db 0Fh,22h,0C2h + endm + +MOV_CR0_ESP macro + db 0Fh,22h,0C4h + endm + +MOV_CR0_EBP macro + db 0Fh,22h,0C5h + endm + +MOV_CR0_ESI macro + db 0Fh,22h,0C6h + endm + +MOV_CR0_EDI macro + db 0Fh,22h,0C7h + endm + +MOV_EAX_CR0 macro + db 0Fh,20h,0C0h + endm + +MOV_EBX_CR0 macro + db 0Fh,20h,0C3h + endm + +MOV_ECX_CR0 macro + db 0Fh,20h,0C1h + endm + +MOV_EDX_CR0 macro + db 0Fh,20h,0C2h + endm + +MOV_ESP_CR0 macro + db 0Fh,20h,0C4h + endm + +MOV_EBP_CR0 macro + db 0Fh,20h,0C5h + endm + +MOV_ESI_CR0 macro + db 0Fh,20h,0C6h + endm + +MOV_EDI_CR0 macro + db 0Fh,20h,0C7h + endm + +MOV_CR2_EAX macro + db 0Fh,22h,0D0h + endm + +MOV_EAX_CR2 macro + db 0Fh,20h,0D0h + endm + +MOV_CR3_EAX macro + db 0Fh,22h,0D8h + endm + +MOV_EAX_CR3 macro + db 0Fh,20h,0D8h + endm + +MOV_DR0_EAX macro + db 0Fh,23h,0C0h + endm + +MOV_DR0_EBX macro + db 0Fh,23h,0C3h + endm + +MOV_DR1_EAX macro + db 0Fh,23h,0C8h + endm + +MOV_DR2_EAX macro + db 0Fh,23h,0D0h + endm + +MOV_DR3_EAX macro + db 0Fh,23h,0D8h + endm + +MOV_DR6_EAX macro + db 0Fh,23h,0F0h + endm + +MOV_DR7_EAX macro + db 0Fh,23h,0F8h + endm + +MOV_EAX_DR0 macro + db 0Fh,21h,0C0h + endm + +MOV_ECX_DR0 macro + db 0Fh,21h,0C1h + endm + +MOV_EDX_DR0 macro + db 0Fh,21h,0C2h + endm + +MOV_EAX_DR1 macro + db 0Fh,21h,0C8h + endm + +MOV_EAX_DR2 macro + db 0Fh,21h,0D0h + endm + +MOV_EAX_DR3 macro + db 0Fh,21h,0D8h + endm + +MOV_EAX_DR6 macro + db 0Fh,21h,0F0h + endm + +MOV_EAX_DR7 macro + db 0Fh,21h,0F8h + endm + +MOV_TR6_EAX macro + db 0Fh,26h,0F0h + endm + +MOV_EAX_TR6 macro + db 0Fh,24h,0F0h + endm + +MOV_TR7_EAX macro + db 0Fh,26h,0F8h + endm + +MOV_EAX_TR7 macro + db 0Fh,24h,0F8h + endm + +; *** 32 bit Register/Immediate moves *** + +MOV_EAX_ macro imm + db 66h, 0B8h + dd imm + endm + +MOV_EBX_ macro imm + db 66h, 0BBh + dd imm + endm + +MOV_ECX_ macro imm + db 66h, 0B9h + dd imm + endm + +MOV_EDX_ macro imm + db 66h, 0BAh + dd imm + endm + +MOV_EDI_ macro imm + db 66h, 0BFh + dd imm + endm + +MOV_ESI_ macro imm + db 66h, 0BEh + dd imm + endm + +MOV_EBP_ macro imm + db 66h, 0BDh + dd imm + endm + +MOV_ESP_ macro imm + db 66h, 0BCh + dd imm + endm + +; *** 32-bit immediate arithmetic instructions + +ADD_EAX_ macro imm + db 66h,05h + dd imm + endm + +ADD_EBX_ macro imm + db 66h,81h,0C3h + dd imm + endm + +ADD_ECX_ macro imm + db 66h,81h,0C1h + dd imm + endm + +ADD_EDX_ macro imm + db 66h,81h,0C2h + dd imm + endm + +SUB_EAX_ macro imm + db 66h,2Dh + dd imm + endm + +SUB_EBX_ macro imm + db 66h,81h,0EBh + dd imm + endm + +SUB_ECX_ macro imm + db 66h,81h,0E9h + dd imm + endm + +SUB_EDX_ macro imm + db 66h,81h,0EAh + dd imm + endm + +CMP_EAX_ macro imm + db 66h,3Dh + dd imm + endm + +CMP_EBX_ macro imm + db 66h,81h,0FBh + dd imm + endm + +CMP_ECX_ macro imm + db 66h,81h,0F9h + dd imm + endm + +CMP_EDX_ macro imm + db 66h,81h,0FAh + dd imm + endm + +; *** New Segment Register/AX moves *** + +MOV_FS_AX macro + db 8Eh,0E0h + endm + +MOV_AX_FS macro + db 8Ch,0E0h + endm + +MOV_GS_AX macro + db 8Eh,0E8h + endm + +MOV_AX_GS macro + db 8Ch,0E8h + endm + +; *** New Segment Register pushes & pops *** + +PUSH_FS macro + db 0Fh,0A0h + endm + +PUSH_GS macro + db 0Fh,0A8h + endm + +POP_FS macro + db 0Fh,0A1h + endm + +POP_GS macro + db 0Fh,0A9h + endm + +; *** New Segment Register offset 16 memory moves *** + +MOV_off16_FS macro off16 + db 8Ch,26h + dw off16 + endm + +MOV_FS_off16 macro off16 + db 8Eh,26h + dw off16 + endm + +MOV_off16_GS macro off16 + db 8Ch,2Eh + dw off16 + endm + +MOV_GS_off16 macro off16 + db 8Eh,2Eh + dw off16 + endm + +; *** General Register 32 bit pushes & pops *** + +PUSH_EAX macro + db 66h + push ax + endm + +POP_EAX macro + db 66h + pop ax + endm + +PUSH_EBX macro + db 66h + push bx + endm + +POP_EBX macro + db 66h + pop bx + endm + +PUSH_ECX macro + db 66h + push cx + endm + +POP_ECX macro + db 66h + pop cx + endm + +PUSH_EDX macro + db 66h + push dx + endm + +POP_EDX macro + db 66h + pop dx + endm + +PUSH_EDI macro + db 66h + push di + endm + +POP_EDI macro + db 66h + pop di + endm + +PUSH_ESI macro + db 66h + push si + endm + +POP_ESI macro + db 66h + pop si + endm + +PUSH_EBP macro + db 66h + push bp + endm + +POP_EBP macro + db 66h + pop bp + endm + +PUSH_ESP macro + db 66h + push sp + endm + +POP_ESP macro + db 66h + pop sp + endm + + +; *** General Register 32 bit xors *** + +XOR_EAX_EAX macro + db 66h + xor ax, ax + endm + +XOR_EBX_EBX macro + db 66h + xor bx, bx + endm + +XOR_ECX_ECX macro + db 66h + xor cx, cx + endm + +XOR_EDX_EDX macro + db 66h + xor dx, dx + endm + +XOR_EBP_EBP macro + db 66h + xor bp, bp + endm + +.list ; end of INSTR386.INC diff --git a/v4.0/src/MEMM/MEMM/IOTRAP.ASM b/v4.0/src/MEMM/MEMM/IOTRAP.ASM new file mode 100644 index 0000000..eb7d79c --- /dev/null +++ b/v4.0/src/MEMM/MEMM/IOTRAP.ASM @@ -0,0 +1,165 @@ + + + page 58,132 +;****************************************************************************** + title IOTRAP.ASM - Dispatches I/O trap handlers +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: IOTRAP.ASM - Dispatches I/O trap handlers +; +; Version: 0.04 +; +; Date: July 1, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 07/01/86 0.03 From ELIMTRAP.ASM +; 07/03/86 0.03 Added handlers for 84,85,60, & 64 +; 07/06/86 0.04 Changed assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; +; This routine is called by all I/O space trap handlers to allow +; emulation/monitoring of I/O address reads and writes. When a GP fault +; occurs due to I/O to an address trapped in the I/O Bit Map, the I/O +; instruction emulation routine in VMINST calls this routine. This +; routine calls the appropriate I/O trap handler for the I/O address. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public IO_Trap ; dispatches I/O trap handlers + +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +FALSE equ 0 +TRUE equ not FALSE + + include VDMseg.inc + include VDMsel.inc + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** + +_TEXT segment + +extrn IOTrap_Tab:word ; System board IO trap routine address table +extrn IOT_BadT:near ; Routine to execute for unknown port +;extrn IOT_LIM:near ; Routine to handle LIM emulated ports +extrn IOT_OEM:near ; Routine to handle OEM specific emulate ports + +_TEXT ends + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP + +;****************************************************************************** +; IO_Trap - Dispatches trap handler for an I/O address +; +; ENTRY: Protected Mode Ring 0 +; AL = byte to output to port. +; DX = port address for I/O. +; SS:BP = points to stack frame on entry to GP fault handler +; BX = 0 => Emulate Input. +; <>0 => Emulate Output. +; +; EXIT: Protected Mode Ring 0 +; AL = emulated input value from port. +; CLC => I/O emulated by LIM_Trap. +; STC => I/O NOT emulated by LIM_Trap. +; +; WARNING:*********** +; This routine is closely allied with IOTBadT which is in TrapDef. +; IOTBadT assumes that the stack is in a certain state! +; *********** +; +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +IO_Trap proc near +; + push ds + push dx + + push VDMD_GSEL + pop ds ; set DS = DGROUP + + cmp dx,0100h ;Q: I/O Addr < 0100h (system brd port)? + jae IOT_NotSys ; N: check mapping regs +IOT_Sys: ; Y: dispatch I/O trap handler + xchg bx, dx ; BL = port address + shl bx,1 ; BX = BX*2 (word table) + call cs:IOTrap_Tab[bx] ; call handler + ; ENTRY: entry DX,DS on stack + ; DS = DGROUP selector + ; BX = 2 * port address in 0100h range + ; DX = input/output flag + + xchg bx,dx ; reset bx + pop dx ; + pop ds ; reset dx + ret ; CF = 1 if I/O not emulated + +; +; Address >= 0100h + +IOT_NotSys: +; +; check for OEM specific I/O emulation +; + call IOT_OEM ;If emulated by OEM specific routine + ; does not return(returns from IO_Trap) +; NOTE : we don't have LIM h/w port anymore +; +; check for LIM mapping register address +; +; call IOT_LIM ;If emulated by LIM emulation routine + ; does not return(returns from IO_Trap) + +; +; Here if I/O Address >= 0100h and not a mapping register +; map it into 1k and try system board ports again +; + and dx,3FFh ; map address into 1k range + cmp dx,0100h ;Q: I/O Addr < 0100h (system brd port)? + jb IOT_Sys ; Y: check system ports + ; N: unknown port + xchg bx,dx ; put Input/Output flag in DX for IOT_BadT + shl bx,1 + call IOT_BadT + jmp $ ;IOT_BadT pops return address off restores regs + ; and returns + +IO_Trap endp + + +_TEXT ends + + end + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/KBD.ASM b/v4.0/src/MEMM/MEMM/KBD.ASM new file mode 100644 index 0000000..3616c1e --- /dev/null +++ b/v4.0/src/MEMM/MEMM/KBD.ASM @@ -0,0 +1,1608 @@ + + +page 58,132 +;****************************************************************************** + title KBD.ASM - - protected mode AT keyboard driver +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMMD.EXE - MICROSOFT Expanded Memory Manager 386 DEBUG Driver +; +; Module: KBD.ASM - - protected mode AT keyboard driver for debugger +; +; Version: 0.04 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; A- Removed STIs and changed CLI/STIs to keep interrupt +; status stable (OFF) during debugger execution. The +; specific problem was in reporting unexpected traps +; fielded from Virtual Mode during DOS execution, +; e.g. timer ticks. +; B- Fixed Ctrl-NumLock, Ctrl-Alt-Del, Ctrl-Break, and +; Shift-PrtSc +; 05/12/86 C Cleanup and segment reorganization +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/05/86 0.04 Moved to DCODE segment +; +;****************************************************************************** +; +; Functional Description: +; +; THIS CODE IS USED BY THE DEBUGGER ONLY ! +; +; This is a PC/AT keyboard driver capable of running +; in protected mode. It does not require any ROM support. +; +; The major modifications are: +; +; - Remove foreign tables, use US only +; - Hard code machine type rather than looking in ROM +; - hard code BeepFreq, BeepDur +; - removed KeyVector, put read-only data in CS +; - removed Accent stuff, which had code writes +; - removed code writes in foreign kbd +; - removed INT 15h sysreq and post +; - removed T&SR stuff, added buffer read routine "getc" +; - made it polled, removed all interrupt stuff +; - changed "data" segment to "romdata" +; +; +; SCCSID = @(#)keybxx.asm 4.1 85/10/09 +;------------------------------------------------------ +; +; KEYBXX - foreign keyboard driver. +; +; April 1985 by Michael Hanson +; Copyright 1985 by Microsoft Corporation +; +; KeybXX is a keyboard handling program using tables +; supplied in a separate file to do foreign language +; keyboard support. It is the basis for the KEYB??.EXE +; programs which use this program and the corresponding +; table defined in KEYB??.ASM. +; +; KeybXX.OBJ must be linked with one of the Keyb??.OBJ +; programs to work, the KEYB?? file must be first. +; See the accompanying makefile for examples. +; +; Note: KEYB?? refers to any of KEYBFR ( French ), +; KEYBGR (German), KEYBUK (United Kingdom), +; KEYBIT (Italian), KEYBSP (Spanish) and +; KEYBDV (Dvorak). These are the currently +; defined data tables for KEYBXX. +; +; Compatability notes: +; 1. The IBM foreign keyboard drivers don't return +; anything for a CTRL-ALT space. This is not +; what I expect from the manuals, but for +; compatibility, KEYBXX doesn't return anything +; in this case either. +; +; 2. For the AT the keyboard driver should do a post +; call (int 15). The ROM keyboard driver does, but +; IBM's foreign keyboard drivers appear not to. +; Currently KEYBXX does a post code, though only +; one is issued at any one time (that is, only 1 post +; call for the 2 characters returned by an illegal +; accent combination). +; +; This program is a modified version of the keyboard handler from - +; +; Microsoft Mach 10 Enhancement Software +; +; Copyright 1984 by Microsoft Corporation +; Written June 1984 by Chris Peters +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + +include VDMseg.inc +include desc.inc +include kbd.inc + + +MASTER_IMR equ 21h ; mask port for master 8259 + +;*** ROM BIOS data area, set up addresses +romdata segment use16 at 40h + org 17h +KeyState db ? +BreakState db ? +AltKey db ? +KbHead dw ? +KbTail dw ? +KbBuffer dw 16 dup (?) +KbBufferEnd label word + + org 49h +VidMode db ? + org 65h +VidReg db ? + + org 71h +fBreak db ? +fReset dw ? + + org 80h +KbStart dw ? +KbEnd dw ? + + org 97h +ATKbFlags db ? +romdata ends + + + +;*** Routines used by data table modules (Keyb??) +public SpecKey +public AlphaKey +public NormalKey +public Keys$2$13 +public CapKey +public Cap$2$13 +public FuncKey +public PadKey +public NumKey +public SpaceKey +public ShiftKey +public ScrollKey +public StateKey +;public AccKey +public AltShiftKey +public BufferFull +public ReBoot +public XBoot +public PrintScreen +public SysReq + + + + +DCODE segment + assume cs:DCODE,ds:romdata,es:nothing + + +;*** Tables for foreign language key layout +; See Keyb?? files for more details + + +;* Actual foreign language key layout +; extrn ForeignTable :word + + +;* Tables to map CNTRL ALT char +; extrn AltChrs :byte +AltChrs label byte +; extrn AltChrsEnd :byte +AltChrsEnd label byte + +; extrn AltMap :byte +AltMap label byte + + +;* Tables to map accented characters +; extrn AccentChTbl :word +AccentChTbl label word + +; extrn AccentMpTbl :word +AccentMpTbl label word + + +;* Table of accent characters, shifted, ALTed and CTRLed. +; defined using the AccChStruc struct +; extrn AccChTbl :word +AccChTbl label word + + + +;*** Internal variables used by KEYBXX interrupt handler +; KeyVector dd ? ; origin of keyboard decode table +;PCType db ? ; type of PC running on +PCType db 0fch ; type of PC running on + +PC_AT = 0FCh ;if anything else, assume PC/XT + +;Accent db 0 ; set for accent key, =0 for none. +;AccentKey dw ? ; last accent key pressed + +; BeepFreq dw PCBeepFreq ;Count for beep half-cycle +BeepFreq dw ATBeepFreq ;Count for beep half-cycle +; BeepDur dw PCBeepDur ;Count of half-cycles to beep +BeepDur dw ATBeepDur ;Count of half-cycles to beep + + +;*** Normal keyboard table, used in CTRL-ALT F1 mode +; +; See Keyb?? files for structure information. +; +ForeignTable label word +KeyMapTable label word + public KeyMapTable + + db 0,0 ;0 + dw BufferFull + db esc,esc ;1 + dw SpecKey + db "1","!" ;2 + dw Keys$2$13 + db "2","@" ;3 + dw Keys$2$13 + db "3","#" ;4 + dw Keys$2$13 + db "4","$" ;5 + dw Keys$2$13 + db "5","%" ;6 + dw Keys$2$13 + db "6","^" ;7 + dw Keys$2$13 + db "7","&" ;8 + dw Keys$2$13 + db "8","*" ;9 + dw Keys$2$13 + db "9","(" ;10 + dw Keys$2$13 + db "0",")" ;11 + dw Keys$2$13 + db "-","_" ;12 + dw Keys$2$13 + db "=","+" ;13 + dw Keys$2$13 + db 8,127 ;14 + dw SpecKey + db 9,0 ;15 + dw NormalKey + db "q","Q" ;16 + dw AlphaKey + db "w","W" ;17 + dw AlphaKey + db "e","E" ;18 + dw AlphaKey + db "r","R" ;19 + dw AlphaKey + db "t","T" ;20 + dw AlphaKey + db "y","Y" ;21 + dw AlphaKey + db "u","U" ;22 + dw AlphaKey + db "i","I" ;23 + dw AlphaKey + db "o","O" ;24 + dw AlphaKey + db "p","P" ;25 + dw AlphaKey + db "[","{" ;26 + dw NormalKey + db "]","}" ;27 + dw NormalKey + db 13,10 ;28 + dw SpecKey + db CtrlShift,(255-CtrlShift) + dw ShiftKey + db "a","A" ;30 + dw AlphaKey + db "s","S" ;31 + dw AlphaKey + db "d","D" ;32 + dw AlphaKey + db "f","F" ;33 + dw AlphaKey + db "g","G" ;34 + dw AlphaKey + db "h","H" ;35 + dw AlphaKey + db "j","J" ;36 + dw AlphaKey + db "k","K" ;37 + dw AlphaKey + db "l","L" ;38 + dw AlphaKey + db ";",":" ;39 + dw NormalKey + db "'",'"' ;40 + dw NormalKey + db "`","~" ;41 + dw NormalKey + db LeftShift,(255-LeftShift) + dw ShiftKey + db "\","|" ;43 + dw NormalKey + db "z","Z" ;44 + dw AlphaKey + db "x","X" ;45 + dw AlphaKey + db "c","C" ;46 + dw AlphaKey + db "v","V" ;47 + dw AlphaKey + db "b","B" ;48 + dw AlphaKey + db "n","N" ;49 + dw AlphaKey + db "m","M" ;50 + dw AlphaKey + db ",","<" ;51 + dw NormalKey + db ".",">" ;52 + dw NormalKey + db "/","?" ;53 + dw NormalKey + db RightShift,(255-RightShift) + dw ShiftKey + db "*",114 ;55 + dw PrintScreen + db AltShift,(255-AltShift) ;56 + dw AltShiftKey + db " "," " ;57 + dw SpaceKey + db CapsState,(255-CapsState) + dw StateKey + db 1,1 ;59 + dw FuncKey + db 2,2 ;60 + dw FuncKey + db 3,3 ;61 + dw FuncKey + db 4,4 ;62 + dw FuncKey + db 5,5 ;63 + dw FuncKey + db 6,6 ;64 + dw FuncKey + db 7,7 ;65 + dw FuncKey + db 8,8 ;66 + dw FuncKey + db 9,9 ;67 + dw FuncKey + db 0,0 ;68 + dw FuncKey + db NumState,(255-NumState) ;69 + dw NumKey + db ScrollState,(255-ScrollState) + dw ScrollKey + db 0,"7" ;71 + dw PadKey + db 1,"8" ;72 + dw PadKey + db 2,"9" ;73 + dw PadKey + db 3,"-" ;74 + dw PadKey + db 4,"4" ;75 + dw PadKey + db 5,"5" ;76 + dw PadKey + db 6,"6" ;77 + dw PadKey + db 7,"+" ;78 + dw PadKey + db 8,"1" ;79 + dw PadKey + db 9,"2" ;80 + dw PadKey + db 10,"3" ;81 + dw PadKey + db 11,"0" ;82 + dw PadKey + db 12,"." ;83 + dw ReBoot + db 0, 0 ;84 (On AT only) + dw SysReq + + + +;*** Tables for keypad with ALT and control +; Same for foreign as normal +AltKeyPad label byte + db 7,8,9,-1 + db 4,5,6,-1 + db 1,2,3 + db 0,-1 + +CtrlKeyPad label byte + db 119,-1,132,-1 + db 115,-1,116,-1 + db 117,-1,118 + db -1,-1 + + + +;*** Table for ALT alphabetical character +; +; Since uses alpha char as index, this is the same +; for normal and foreign keyboards. +; +AltTable label byte +; a, b, c, d, e, f, g, h, i, j, k, l, m + db 30,48,46,32,18,33,34,35,23,36,37,38,50 +; n, o, p, q, r, s, t, u, v, w, x, y, z + db 49,24,25,16,19,31,20,22,47,17,45,21,44 + + + + SUBTTL Keyboard Interrupt Handler + + +;*** Keyboard interrupt handler +; +handler proc near + +KbInt: +;* sti + cld + push ax + push bx + push cx + push dx + push si + push di + push ds + push es + +; First see if there is any data in the kbd buffer. +; Return to caller if not. + + in al, KbStatus + test al, 1 + jnz intr1 + jmp RestoreRegs +intr1: + + mov ax,romdata + mov ds,ax + call GetSCode ;Get scan code from keyboard in al + mov ah,al ;(ah) = scan code + cmp al,-1 + jnz KbI1 + jmp BufferFull ;go handle overrun code +KbI1: + mov bx,ax + and bx,7fh ;(bl) = scan code without break bit + cmp bl,84 + jle KBI2 + jmp KeyRet ;ignore code if not in range +KBI2: + shl bx,1 ;index into lookup table + shl bx,1 +;* Check for CTRL-ALT chars + test ah, 80h ;no CTRL-ALT remap on break code + jnz KbI23 +; cmp word ptr [KeyVector],offset KeyMapTable +; je KbI23 ;Not foreign keyboard + jmp KbI23 + test [KeyState], CtrlShift + jz KbI23 + test [KeyState], AltShift + jz KbI23 + push ax ; save scan code + +;* map CTRL-ALT char +; look up chars in table, if found then put out corresponding +; entry from map table. + mov si, offset AltChrs - 1 ;Set up index to lookup +KbI21: + inc si ; Advance to next entry + cmp si, offset AltChrsEnd + jae KbI22 ;at end of table, so no remap + cmp ah, cs:[si] + jne KbI21 ;this isn't it so loop +; Found character, so do the mapping + sub si, offset AltChrs + add si, offset AltMap ;get index into remaped table + pop ax ;get scan code + mov al, cs:[si] ;get new character to use + jmp PutKRet +KbI22: + pop ax +KbI23: + +; les si,[KeyVector] + mov si, offset KeyMapTable + mov cx,cs:[si+bx] ;(cx) = lc, uc bytes + mov al,cl ;(al) = lc code for key + mov dl,[KeyState] ;(dl) = keyboard flags + jmp word ptr cs:[si+bx+2] ;Call appropriate key handler +;*** +; for all key handler routines, +; +; (CX) = uc, lc code bytes from table +; (DL) = keyboard flags byte (see equates above for bits) +; (AL) = lc code from cl +; (AH) = scan code from keyboard + +handler endp + + + SUBTTL Key Routines + +;*** Key handling routines, called as specified by the key table + +;------------------------------------------------------ +; +; Alphabetical key, caps lock works as do CTRL and ALT +; +AlphaKey: + call NoBreak + test dl,AltShift + jz ak1 + cbw + add bx,ax + mov ah,[AltTable+bx-"a"] + jmp MakeAlt + +ak1: test dl,CtrlShift + jz ak2 + sub al,"a"-1 + jmp PutKRet + +ak2: xor bh,bh + test dl,RightShift+LeftShift + jz ak3 + or bh,CapsState +ak3: mov cl,dl + and cl,CapsState + xor bh,cl + jz ak4 + mov al,ch +ak4: jmp PutKRet + + +;------------------------------------------------------ +; +; Keys that do something different when CTRL is down +; +SpecKey: + call NoAlt + test dl,CtrlShift + jz bsp1 + mov al,ch +bsp1: jmp PutKRet + + +;----------------------------------------------------- +; +; Normal, Non Alphabetic key +; +NormalKey: ;These return nothing on ALT + call NoAlt + test dl,CtrlShift + jz nk0 + jmp short Ca20 ;ky21 + +Keys$2$13: ;Keys #2 - 13 have ALT codes 120,... + call NoBreak + test dl,AltShift + jz Ky2 + add ah,120-2 + jmp MakeAlt + +ky2: test dl,CtrlShift + jnz Ca20 ;handle CTRL key same as for CapKey +nk0: + test dl,RightShift+LeftShift + jz nk1 + mov al,ch +nk1: jmp PutKRet + + +;----------------------------------------------------- +; +; Non Alphabetic key for which cap lock works +; +CapKey: ; CAPLOCK works, ALT doesn't + call NoAlt + test dl,CtrlShift + jz ca5 + jmp short ca20 ;ca3 + +Cap$2$13: ; KEYS 2-13 with CAPLOCK working + call NoBreak + test dl,AltShift + jz ca2 + add ah,120-2 + jmp MakeAlt + +ca2: test dl,CtrlShift + jz ca5 +ca20: cmp ah, 3 ;Keep CTRL keys at same scan code locations + jnz ca21 + jmp MakeAlt +ca21: cmp ah, 7 + jnz ca22 + mov al, 30 + jmp short ca7 +ca22: cmp ah, 26 + jnz ca23 + mov al, 27 + jmp short ca7 +ca23: cmp ah, 27 + jnz ca24 + mov al, 29 + jmp short ca7 +ca24: + cmp ah, 43 + jnz ca25 + mov al, 28 + jmp short ca7 +ca25: cmp al, '-' ;Except for - key, which moves around. + jnz ca26 + mov al, 31 + jmp short ca7 +ca26: jmp KeyRet + + +ca5: xor bh,bh + test dl,RightShift+LeftShift + jz ca6 + or bh,CapsState +ca6: mov cl,dl + and cl,CapsState + xor bh,cl + jz ca7 + mov al,ch +ca7: jmp PutKRet + + +;--------------------------------------------------- +; +; Scroll Lock, Caps Lock, Num Lock +; +ScrollKey: + test ah,80h + jnz stk0 + test dl,CtrlShift + jz stk1 + mov ax,[KbStart] + mov [KbHead],ax + mov [KbTail],ax + mov [fBreak],80h + call EnableKB +;*a int 1bh +;*a xor ax,ax + mov ax,0003 ;*a simulate ^C + jmp PutKRet + +NumKey: ; NUM LOCK key + test ah,80h + jnz stk0 + test dl,CtrlShift + jz stk1 + or [BreakState],HoldState ; CTRL NUMLOCK + call VideoOn +nlk1: + call handler ;*a (look for key since no interrupts) + test [BreakState],HoldState ; Wait for a key press + jnz nlk1 + jmp RestoreRegs + +StateKey: ; Toggle key + test ah,80h + jz stk1 +stk0: and [BreakState],ch ; Indicate key no longer held down + jmp short shf4 + +stk1: mov ah,al + and al,[BreakState] + jnz shf4 ; Ignore if key already down + or [BreakState],ah ; Indicate key held down + xor dl,ah ; Toggle bit for this key + jmp short shf3 ; And go store it. + + +;--------------------------------------------------- +; +; Alt Shift +; +AltShiftKey: + test ah,80h + jz shf2 ; Indicate that ALT key down + xor al,al + xchg al,[AltKey] ; Find numeric code entered + or al,al + jz shf1 ; Just reset indicator if none + and [KeyState],ch + xor ah,ah ; Make it a key with 0 scan code + jmp PutKRet + +;---------------------------------------------------- +; +; Shift, Ctrl +; +ShiftKey: + test ah,80h + jz shf2 +shf1: and dl,ch ; Unset indicator bit for break code + jmp short shf3 +shf2: or dl,al ; Set indicator bit for make code +shf3: mov [KeyState],dl +shf4: jmp KeyRet + + +;---------------------------------------------------- +; +; Reboot System? +; +ReBoot: call NoBreak ; Del key pressed, check CTRL ALT DEL + test dl,AltShift + jz pdk2 + test dl,CtrlShift + jz pdkx +XBoot: ; Reboot system. + mov ax,romdata ; ds = romdata segment + mov ds,ax + mov [fReset],1234h +;*a +;*a 02/12/86 - use shutdown code 10 and [40:67] to return to real mode +;*a and enter the ROM at the CTRL-ALT-DEL entry point +;*a + cli ; make sure + mov al,0Fh or 80h ; shutdown byte address/disable NMI + out 70h,al ; write CMOS address + jmp short $+2 ; (delay) + mov al,0Ah ; Shutdown code 10 = jump [dword @40:67] + out 71h,al ; write shutdown code to shutdown byte +; +; Set up entry point after the reset +; + mov ds:[67h],0EA81h ; offset of CTRL-ALT-DEL entry point + mov ds:[67h+2],0F000h ; segment of CTRL-ALT-DEL entry point +; +; Reset the CPU +; + mov al,0FEh ; FEh = pulse output bit 0 (286 reset) + out 64h,al ; command to 8042 + hlt ; don't want to coast +;*a +;*a end inserted code +;*a +;*a mov ax,-1 +;*a push ax +;*a xor ax,ax +;*a push ax +;*a xxx proc far +;*a ret ; To reboot system, do a far return to FFFFh:0 +;*a xxx endp + + +;---------------------------------------------------- +; +; Key Pad Key +; +PadKey: + mov bl,[AltKey] + call NoBreak2 + test dl,AltShift + jz pdk2 ; Not entering a character number + xor bx,bx + mov bl,cl + mov cl,cs:AltKeyPad[bx] ; Get numeric value for this key + cmp cl,-1 + jz pdk0 ; Start over if non-digit key + mov al,10 + mul [AltKey] + add al,cl + jmp short pdk1 +pdk0: xor ax,ax +pdk1: mov [AltKey],al +pdkx: jmp KeyRet + +pdk2: mov al,0 + test dl,CtrlShift + jz pdk3 + xor bx,bx ; Lookup CTRL keypad key code + mov bl,cl + mov ah,cs:CtrlKeyPad[bx] + jmp short pdk6 +pdk3: cmp ah,74 ; - key independent of shift state + jz pdk41 + cmp ah,78 ; + key independent of shift state + jz pdk41 + xor bx,bx + test dl,RightShift+LeftShift + jz pdk4 + or bh,NumState +pdk4: mov cl,dl + and cl,NumState + xor bh,cl + jz pdk5 +pdk41: mov al,ch ; use char2 if shifted or in numlock +pdk5: or al,al + jnz pdk7 +pdk6: cmp ah,-1 + jz pdk8 ; Ignore CTRL with keypad 2, etc. + cmp ah,76 + jz pdk8 +pdk7: jmp PutKRet +pdk8: jmp KeyRet + + +;---------------------------------------------------- +; +; Function Key +; +FuncKey: + call NoBreak + test dl,AltShift+CtrlShift+LeftShift+RightShift + jz fk1 ; Normal function key + add ah,84-59 + test dl,AltShift+CtrlShift + jz fk1 ; Shifted function key + add ah,10 + test dl,AltShift + jz fk1 ; Just CTRL function key + add ah,10 + test dl,CtrlShift + jz fk1 ; Just ALT function key + mov bx,offset KeyMapTable + cmp ah,104 ; CTRL ALT f1 to use normal keyboard + jz fk01 + cmp ah,105 ; CTRL ALT f2 for foreign keyboard + jnz fk1 ; if not F1 or F2 then treat as ALT + mov bx,offset ForeignTable +fk01: + cli ; Change translation table used +; mov word ptr [KeyVector],bx +; mov word ptr [KeyVector+2],cs + jmp KeyRet + +fk1: jmp MakeAlt + + +;-------------------------------------------------------------------- +; +; Print Screen Key +; +PrintScreen: + call NoAlt + test dl,CtrlShift + jz ps1 + mov ah,ch + jmp fk1 +ps1: test dl,LeftShift+RightShift + jz pdk7 + call VideoOn ;CTRL PrtSc - enable video and do Print Screen +;*a int 5 + jmp RestoreRegs + + +;-------------------------------------------------------------------- +; +; Space Key +; +SpaceKey: + call NoBreak + test dl, CtrlShift + jz sp1 + test dl, AltShift + jz sp1 + jmp KeyRet ; Don't return anything on CTRL-ALT space +sp1: + jmp PutKRet + + +;-------------------------------------------------------------------- +; +; An accent key +; +; Each accent key is assumed to be accent both non-shifted +; and shifted, and the accent number for the shifted should +; be the next one up from the unshifted accent number. +; +;AccKey: +; call NoBreak +; cbw ;convert accent number to an index +; mov bx, ax +; dec bx +; shl bx,1 +; shl bx,1 ;index to table of AccChStruc's +; test dl, altshift +; jz acc2 ;ALT not down +; mov ax, [AccChTbl+bx].alt +; jmp short acc5 +;acc2: +; test dl, ctrlshift +; jz acc3 ;just a normal or shifted keypress +; mov ax, [AccChTbl+bx].ctrl +; jmp short acc5 +;acc3: +; test dl, leftshift+rightshift +; jz acc4 ; not shifted (caps lock not used) +; mov Accent,ch ; Get shifted accent number +; mov ax, [AccChTbl+bx].shift +; mov AccentKey, ax ; Save key and scn code next key int +; jmp KeyRet +;acc4: +; mov Accent, al +; mov ax, [AccChTbl+bx].normal +; mov AccentKey, ax +; jmp KeyRet +;acc5: +; jmp PutKRet +; + + +;-------------------------------------------------------------------- +; +; System Request Key +; +SysReq: + test ah, 80h + jnz sys2 ;this is break code + test BreakState, SysShift + jz sys1 + jmp KeyRet ;Ignore if SysReq already down + +sys1: + or BreakState, SysShift ;set held down flag + mov ax, 08500h + jmp short sys3 +sys2: + and BreakState, Not SysShift ;turn off held down flag + mov ax, 08501h +sys3: + push ax ; Save SysReq action number + mov al,20h ; EOI to control port +; out 20h,al + call EnableKB + pop ax +; int 15h ; Indicate SysReq to BIOS + jmp RestoreRegs + + + + +;*** Finish up processing of interrupt +; + +;* Make this an ALT seq by removing chr code (ret scan code, 0) +MakeAlt:mov al,0 + +;* Put Key in buffer and return +PutKRet: +; cmp Accent, 0 ; check for accented char +; je puk3 ;no accent pressed, just put out key +; mov bl, Accent +; dec bl ;make accent no an index +; xor bh,bh +; mov Accent, bh ;Accent only this character +; shl bx,1 ;index into word table +; mov si, AccentChTbl[bx] ;Get pointer to string for this accent +; dec si ;Negate effect of initial inc in loop +;puk1: +; inc si +; cmp al,cs:[si] +; jz puk2 ;This is an accentable char - so remap +; cmp byte ptr cs:[si], 0 +; jnz puk1 ;not done yet +; +;;* The character is not in this list, so do a beep and put +;; out booth accent char and this char +; call ErrBeep +; mov bx,ax +; mov ax,AccentKey ;Put out accent +; call PutKey +; mov ax,bx +; cmp al, ' ' +; je puk4 ;Char is space, just beep and put out accent. +; jmp short puk3 ;Put out the character +; +;puk2: +; xor ah, ah ;Zero scan code for accented chrs +; cmp al, 0 ;for accented ALT chr put out 0, don't beep +; je puk3 +; sub si, AccentChTbl[bx] ; Make index to map table +; add si, AccentMpTbl[bx] +; mov al, cs:[si] ; Get remapped char +puk3: + call PutKey +puk4: + cmp [PCType],PC_AT + jnz KeyRet ; just return for non-AT + cli + mov al,20h ; EOI to control port +; out 20h,al + call EnableKB +; mov ax, 09102h ; Send a post code +; int 15h + jmp RestoreRegs + + + +;* Common validity check routines (Check for ALT, ignore break codes) +; + +NoAlt: test dl,AltShift ; Don't allow ALT with this key + jnz IgB1 +NoBreak: ; Ignore break code for this key + mov bl,0 +NoBreak2: + test ah,80h + jnz IgB1 + test [BreakState],HoldState ; in hold state? + jz IgB0 ; no... + and [BreakState],(255-HoldState) + jmp short IgB1 +IgB0: mov [AltKey],bl + ret +IgB1: pop ax ; pop off return address + jmp short KeyRet + + +;* buffer is full, beep the speaker and return from interrupt +BufferFull: + cli + mov al,20h +; out 20h,al + call ErrBeep + jmp short KeyRet1 + + +;* Normal return from interrupt, handle EOI and enable KB +KeyRet: + cli + mov al,20h +; out 20h,al +KeyRet1: + call EnableKB +RestoreRegs: + cli + pop es + pop ds + pop di + pop si + pop dx + pop cx + pop bx + pop ax +ppp proc near + ret +ppp endp +; iret + + + SUBTTL Subroutines + + + + +;*** VideoOn - enable keyboard and video +; +; ENTRY: Nothing +; +; EXIT: (dx), (al) destroyed. +; +VideoOn proc near + mov al,20h ; EOI to control port +; out 20h,al + call EnableKB ; Enable AT keyboard + cmp [VidMode],7 + jz vdo1 ; Do nothing for monochrome monitor + mov al,[VidReg] + mov dx,3d8h + out dx,al ; Enable video controller +vdo1: ret +VideoOn endp + + + + +;*** EnableKB - Enable the keyboard interface on an AT, no effect on PC/XT. +; +; ENTRY: Nothing +; +; EXIT: (al) destroyed +; +; EFFECTS: Enables the Keyboard interface. +; +EnableKB proc near + cmp [PCType], PC_AT + jne ena1 ;for non-AT simply ignore + pushf ;* save interrupt status + cli + call WaitStatus + mov al,0AEh ;output enable keyboard command + out KbStatus,al + popf ;* restore original interrupt status +;* sti +ena1: + ret +EnableKB endp + + + + +;*** DisableKB - Disable the keyboard interface on an AT, no effect on PC/XT +; +; ENTRY: Nothing +; +; EXIT: (al) destroyed +; +; EFFECTS: Disables the Keyboard interface. +; +DisableKB proc near + cmp [PCType], PC_AT + jne dis1 ; Ignore if not an AT + pushf ;* save interrupt status + cli + call WaitStatus + mov al,0ADh ;output disable command + out KBStatus, al + popf ;* restore original interrupt status +;* sti +dis1: + ret +DisableKB endp + + + + +;*** ErrBeep - beep the speaker +; +; ENTRY: Nothing +; +; EXIT: Nothing +; +; USES: (ax) - to access I/O port +; (bx) - length of beep in cycles +; (cx) - counter for cycle length +; +; EFFECTS: Speaker is beeped +; +; WARNING: Uses in/out to keyboard port to beep speaker directly. +; +ErrBeep proc near + push ax + push bx + push cx + mov bx,BeepDur ; count of speaker cycles + in al,KbCtl + push ax + and al,0fch ; turn off bits 0 and 1 (speaker off) +bee1: xor al,2 ; toggle speaker bit + out KbCtl,al + mov cx,BeepFreq +bee2: loop bee2 ; wait for half cycle + dec bx + jnz bee1 ; keep cycling speaker + pop ax ; restore speaker/keyboard port value + out KbCtl,al + pop cx + pop bx + pop ax + ret +ErrBeep endp + + + + +;*** PutKey - put key in the buffer +; +; ENTRY: (ax) = key code and scn code to go in buffer +; +; EXIT: (si), (di) destroyed. +; ints disabled. +; +; EFFECTS: KbTail updated +; (ax) put in buffer at end. +; On AT - do post call. +; +; If it isn't possible to put key in buffer (full) then beep +; and ignore. +; If (ax) = -1 then the key is not put in buffer. +; +PutKey proc near + cmp ax, -1 ; Code to ignore a key + jz put2 + cli ; Make sure only ones using buffer now + mov si,[KbTail] + mov di,si ; Get old buffer end and save it + inc si ; Advance pointer + inc si + cmp si,[KbEnd] + jb put01 + mov si,[KbStart] ; Wrap to beginning if at end +put01: + cmp si,[KbHead] + jnz put1 ; Buffer not Full + pop ax ; Drop return address + jmp BufferFull ; Go beep and return from interrupt + +put1: + mov [di],ax ; Put key in buffer at end + mov [KbTail],si +put2: + ret +PutKey endp + + + + +;*** GetSCode - read the scan code from the keyboard +; +; ENTRY: nothing +; +; EXIT: (al) = key scan code from keyboard +; (ah) destroyed +; +; USES: PCType - to use PC/AT sequence, for AT - handles LEDs +; +GetSCode proc near + cmp [PCType], PC_AT + je gsc1 ;handle AT differently + in al,KbData ;get key code + xchg bx,ax ;save scan code + in al,KbCtl ;acknowledge to keyboard + mov ah,al + or al,80h + out KbCtl,al + xchg ah,al + out KbCtl,al + xchg ax,bx ;(al) = scan code + ret + +gsc1: ;have to do handshake + call DisableKB + pushf ;* save interrupt status + cli + call WaitStatus + in al,KbData ;read in character + popf ;* restore original interrupt status +;* sti + +; check for and flag control bytes from keyboard + cmp al,ATResend + jne gsc2 ;it isn't a resend + cli + or [ATKbFlags], KbResend + pop bx ;throw away return address + jmp KeyRet ;and don't do anything more with key + +gsc2: + cmp al,ATAck + jne gsc3 ;it isn't an ack + cli + or [ATKbFlags], KBAck + pop bx ;throw away return address + jmp KeyRet ;and don't do anything more with key + +gsc3: + call UpdateLeds ;update AT's leds + ret +GetSCode endp + + + +;*** Don't need to keep code after here when not running on an AT +xt_endcode: + + + +;*** UpdateLeds - update the leds on the AT keyboard +; +; ENTRY: Nothing +; +; EXIT: All regs preserved +; +; EFFECTS: Sets the keyboard LEDs according to the status byte. +; +; WARNING: Assumes it is operating on an AT, must not be called for a PC. +; +UpdateLeds proc near + pushf ;* save interrupt status + push ax + cli + mov ah, KeyState ; get the toggle key states + and ah, CapsState + NumState + ScrollState + rol ah, 1 + rol ah, 1 + rol ah, 1 + rol ah, 1 ; in format for ATKbFlags + mov al, ATKbFlags + and al, 07h + cmp ah, al + jz Updn1 ; No change in leds, so don't update + test ATKbFlags, KBSndLed + jnz Updn1 ; Already updating, so don't update + or ATKbFlags, KBSndLed + mov al, 20h +; out 20h, al ; send EOI + mov al, 0EDh ; Set indicators command + call SendByte + test ATKbFlags, KBErr + jnz Updn2 + mov al, ah ; Send indicator values + call SendByte + test ATKbFlags, KBErr + jnz Updn2 + and ATKbFlags, 0F8h + or ATKbFlags, ah ; Record indicators +Updn2: + and ATKbFlags, Not (KBSndLed + KBErr) +Updn1: + pop ax + popf ;* restore original interrupt status +;* sti + ret +UpdateLeds endp + + + + +;*** SendByte - send a byte to the keyboard +; +; ENTRY: (al) - command/data to send +; +; EXIT: BreakState flags set according to success of operation. +; Ints disabled on completion. +; +; USES: (al) - byte to send. +; (ah) - count of retries. +; (cx) - time out counter on wait for response. +; +; Send the byte in al to the AT keyboard controller, and +; do handshaking to make sure they get there OK. +; Must not be called for the PC. +; +SendByte proc near + push ax + push cx + mov ah, 03 ; Set up count of retries +Sen1: + pushf ;* save interrupt status + cli + and ATKbFlags, Not (KBResend + KBAck + KBErr) + push ax ; save byte to send + call WaitStatus ; Wait for keyboard ready + pop ax + out KbData, al ; Send byte to keyboard + popf ;* restore original interrupt status +;* sti + mov cx,2000h ; Time out length, Approximate value for AT ROM +Sen2: ; Wait for ACK + call handler ;*a (look for key since no interrupts) + test ATKbFlags, KBResend + KBAck + jnz Sen4 + loop Sen2 +Sen3: ; Timed out - try to resend + dec ah + jnz Sen1 + or ATKbFlags, KBErr + jmp Sen5 +Sen4: + call handler ;*a (look for key since no interrupts) + test ATKbFlags, KBResend + jnz Sen3 +Sen5: + cli + pop cx + pop ax + ret +SendByte endp + + + + +;*** WaitStatus - wait for status to indicate ready for new command +; +; ENTRY: Nothing +; +; EXIT: (AL) Destroyed. +; +WaitStatus proc near + push cx + xor cx,cx +wai1: ;wait for empty buffer + in al,KbStatus + test al,BufFull + loopnz wai1 + pop cx + ret +WaitStatus endp + + SUBTTL Initialization + + + +;* Initialization, called when run by DOS, doesn't stay resident. +; +init_bios: + + mov al,0ffh ; all OFF + out MASTER_IMR,al + + push ds + push cs + pop ds ; establish segment, since offsets are from cs + mov dx,offset Kbint + mov ax,2509h + int 21h ;Set interrupt 9 (keyboard) vector + + mov ax, romdata + mov ds, ax +init1: cmp [KbStart],0 + jnz init2 ;New PC/AT - KbStart already initialized + pushf ;* save interrupt status + cli ;For old PC - initialize pointers to KbBuffer + mov ax,offset KbBuffer + mov [KbStart],ax + mov [KbHead],ax + mov [KbTail],ax + mov [KbEnd],offset KbBufferEnd + popf ;* restore original interrupt status +;* sti +init2: ; Start up in Foreign keyboard mode +; mov word ptr [KeyVector],offset ForeignTable +; mov word ptr [KeyVector+2],cs + +; mov [accent],0 ; No previous accent key pressed + +; Get PC type information and save in PCType flag +; assume ds:rom + +; mov ax, rom +; mov ds, ax +; mov al, [systid] +; mov [PCType], al + + assume ds:romdata + pop ds + +; mov dx,offset xt_endcode + 100h +; cmp [PCType], PC_AT +; jnz init6 ; Drop AT specific code + +;* Initialization specific to AT +; Set up speaker counts, exchange keys 41, 43 +; And keep AT specific code when terminate +; mov [BeepFreq], ATBeepFreq +; mov [BeepDur], ATBeepDur + +; Reverse keys 41 and 43 for foreign keyboards +; mov ax, [ForeignTable + (41 * 4)] ; exchange char codes +; xchg ax, [ForeignTable + (43 * 4)] +; mov [ForeignTable + (41 * 4)], ax +; mov ax, [ForeignTable + (41 * 4) + 2] ;exchange function codes also +; xchg ax, [ForeignTable + (43 * 4) + 2] +; mov [ForeignTable + (41 * 4) + 2], ax +; Also handle for Ctrl Alt table +; mov si, offset AltChrs - 1 +;init3: ;search AltChrs table +; inc si +; cmp si, offset AltChrsEnd +; jae init5 ;Done scaning - go terminate +; cmp byte ptr cs:[si], 43 +; jnz init4 +; mov byte ptr cs:[si], 41 ; found key 43 - replace with 41 +; jmp init3 +;init4: +; cmp byte ptr cs:[si], 41 +; jnz init3 +; mov byte ptr cs:[si], 43 ; found key 41 - replace with 43 +; jmp init3 +; +;init5: +; mov dx,offset init_bios + 100h ; Keep AT specific code +init6: +; Terminate and stay resident, don't keep init code +; push ds ; adjust cs to psp +; mov bx, offset init7 + 100h ; by doing a far return to init7 +; push bx +;xxxx proc far +; ret +;xxxx endp +;init7: +; int 27h + + mov ah, 14 + mov al, 'i' + int 10h +ini1: + + ;mov ah, 14 + ;mov al, 'h' + ;int 10h + + call handler +; call getc + jz ini1 + mov ah, 14 + int 10h + jmp ini1 + +DCODE ends + +;*** getc - read character out of keyboard buffer +; +; This routine gets characters from the buffer +; in the ROM data area. +; +; ENTRY +; +; EXIT AL - character +; AH - scan code +; 'Z' = 0 +; +; or 'Z' = 1 if no code available +; +; USES flags +; + +DCODE segment + + assume cs:DCODE, ds:nothing, es:nothing, ss:nothing + + public kgetc +kgetc proc far + + push bx + push cx + push dx + push si + push di + + mov bx, 202h + mov cx, 303h + mov dx, 404h + mov si, 505h + mov di, 606h + + call handler ; pull data into kbd buffer + + mov bx, 2020h + mov cx, 3030h + mov dx, 4040h + mov si, 5050h + mov di, 6060h + + push ds ; save caller's regs + push bx + + mov bx, romdata + mov ds, bx ; DS -> ROM data area + + cli + mov bx, ds:[KbHead] ; bx = start of buffer + cmp bx, ds:[KbTail] ; is buffer empty +;* sti + jz ge1 + + cli + mov ax, [bx] ; AX = character and scan code + add bx, 2 ; step buffer pointer + cmp bx, ds:[KbEnd] ; is it at end of buffer + jne ge2 + mov bx, ds:[KbStart] ; move it back to start +ge2: + mov ds:[KbHead], bx ; store new start pointer +;* sti + and bx, 0ffffh ; just to clear zero flag +ge1: + pop bx + pop ds + + pop di + pop si + pop dx + pop cx + pop bx + + ret + +kgetc endp + +DCODE ends + end + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/KBD.INC b/v4.0/src/MEMM/MEMM/KBD.INC new file mode 100644 index 0000000..ce3ca1a --- /dev/null +++ b/v4.0/src/MEMM/MEMM/KBD.INC @@ -0,0 +1,99 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: KBD.INC - KBD.ASM Structures and Equates +; +; Version: 0.02 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +; +; Functional Description: +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +; SCCSID = @(#)keybxx.inc 1.1 85/10/09 +;------------------------------------------------------ +; +; Keybxx.inc - Define struct and equates for KeybXX and Keyb??.ASM . +; +; Keyb?? - denotes any of the files keybfr, keybgr, keybit, keybuk, +; keybsp or keybdv (Dvorak keyboard). +; + + +esc equ 1bh + + +KbData equ 60h ; I/O Ports for keyboard +KbCtl equ 61h +KbStatus equ 64h + +PCBeepFreq equ 48h ; Count for Beep frequency +PCBeepDur equ 105h ; Number of Beep half cycles +ATBeepFreq equ 0CEh ; Use larger values since AT faster +ATBeepDur equ 82h + +InsState equ 80h ; Bit values for BreakState and KeyState +CapsState equ 40h +NumState equ 20h +ScrollState equ 10h +HoldState equ 08h + + +AltShift equ 08h ; Bit values for KeyState +CtrlShift equ 04h +LeftShift equ 02h +RightShift equ 01h + + +BufFull equ 02h ; Bit value for KbStatus port + + +ATResend equ 0FEh ; AT keyboard commands +ATAck equ 0FAh + + +KBErr equ 080h ; Bit values for ATKbFlags +KBSndLed equ 040h +KBResend equ 020h +KBAck equ 010h +SysShift equ 004h ;SysReq key held down + + +;*** AccChStruc - Structure for information about accent keys +; +; Contains scan and char codes returned for all shift combinations +; with an accent key. +; +; Note: an accent key is an accent in both normal and shifted mode. +; +AccChStruc struc +normal dw 0 ;chr & scan code for unshifted accent key +shift dw 0 ; " " " for shifted " " +ctrl dw -1 +alt dw -1 +AccChStruc ends + +.list ; end of KBD.INC diff --git a/v4.0/src/MEMM/MEMM/LOADALL.INC b/v4.0/src/MEMM/MEMM/LOADALL.INC new file mode 100644 index 0000000..bd31ec4 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/LOADALL.INC @@ -0,0 +1,173 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; **** INTEL PROPRIETARY **** +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: LOADALL - contains structures for 286 and 386 loadall +; +; Version: 0.02 +; +; Date: April 11,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/11/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +; +ifndef INC_LIST +.xlist +endif + +LODAL286 equ 050Fh ; instruction as a WORD +LODAL386 equ 070Fh ; instruction as a WORD + +;****************************************************************************** +; +; Note that entries are statically initialized to 0000, so limits and +; access rights must be set up at run time. +; +; Structure of a 286 system table/segment descriptor cache: +; +DescCache286 struc +dc2_BASElo dw 0000 ; low word of base (0..15) +dc2_BASEhi db 00 ; high byte of base (16..24) +dc2_AR db 00 ; access rights byte +dc2_LIMIT dw 0000 ; segment limit +DescCache286 ends +; +; Structure of the 286 LOADALL buffer +; +LoadAllBuf286 struc + +ll2_None1 db 6 dup (0) ; temp +ll2_MSW dw 0000 ; MSW +ll2_None2 db 14 dup (0) ; temp +ll2_TR dw 0000 ; TR +ll2_FLAGS dw 0000 ; FLAGS +ll2_IP dw 0000 ; IP +ll2_LDT dw 0000 ; LDT +ll2_DS dw 0000 ; DS +ll2_SS dw 0000 ; SS +ll2_CS dw 0000 ; CS +ll2_ES dw 0000 ; ES +ll2_DI dw 0000 ; DI +ll2_SI dw 0000 ; SI +ll2_BP dw 0000 ; BP +ll2_SP dw 0000 ; SP +ll2_BX dw 0000 ; BX +ll2_DX dw 0000 ; DX +ll2_CX dw 0000 ; CX +ll2_AX dw 0000 ; AX + +; +; System table and segment descriptor caches +; +ll2_EScache db size DescCache286 dup (00) +ll2_CScache db size DescCache286 dup (00) +ll2_SScache db size DescCache286 dup (00) +ll2_DScache db size DescCache286 dup (00) +ll2_GDTcache db size DescCache286 dup (00) +ll2_LDTcache db size DescCache286 dup (00) +ll2_IDTcache db size DescCache286 dup (00) +ll2_TSScache db size DescCache286 dup (00) + +LoadAllBuf286 ends +; + +; +;****************************************************************************** +; Define the 386 LOADALL buffer structure - 'nested' structures must be +; used because the complete definition is too complex for the linker. +; Note that entries are statically initialized to 0000, so limits and +; access rights must be set up at run time. +; +; Structure of a 386 system table/segment descriptor cache: +; +DescCache386 struc +dc3_AR1 db 00 ; base 16..23 (ignored) +dc3_AR2 db 00 ; access rights byte +dc3_AR3 db 00 ; limit 16..19 (ignored), B/D, G +dc3_AR4 db 00 ; base 24..31 (ignored) +dc3_BASElo dw 0000 ; low word of base +dc3_BASEhi dw 0000 ; high word of base +dc3_LIMITlo dw 0000 ; low word of limit +dc3_LIMIThi dw 0000 ; high word of limit +DescCache386 ends +; +; Structure of the 386 LOADALL buffer +; +LoadAllBuf386 struc + +ll3_CR0 dw 0000 ; low word of CR0 +ll3_CR0hi dw 0000 ; high word of CR0 +ll3_EFLAGS dw 0000 ; low word of EFLAGS +ll3_EFLAGShi dw 0000 ; high word of EFLAGS +ll3_EIP dw 0000 ; low word of EIP +ll3_EIPhi dw 0000 ; high word of EIP +ll3_EDI dw 0000 ; low word of EDI +ll3_EDIhi dw 0000 ; high word of EDI +ll3_ESI dw 0000 ; low word of ESI +ll3_ESIhi dw 0000 ; high word of ESI +ll3_EBP dw 0000 ; low word of EBP +ll3_EBPhi dw 0000 ; high word of EBP +ll3_ESP dw 0000 ; low word of ESP +ll3_ESPhi dw 0000 ; high word of ESP +ll3_EBX dw 0000 ; low word of EBX +ll3_EBXhi dw 0000 ; high word of EBX +ll3_EDX dw 0000 ; low word of EDX +ll3_EDXhi dw 0000 ; high word of EDX +ll3_ECX dw 0000 ; low word of ECX +ll3_ECXhi dw 0000 ; high word of ECX +ll3_EAX dw 0000 ; low word of EAX +ll3_EAXhi dw 0000 ; high word of EAX +ll3_DR6 dw 0000 ; low word of DR6 +ll3_DR6hi dw 0000 ; high word of DR6 +ll3_DR7 dw 0000 ; low word of DR7 +ll3_DR7hi dw 0000 ; high word of DR7 +ll3_TSSR dw 0000 ; TSSR (TSS selector) + dw 0000 ; (padding) +ll3_LDTR dw 0000 ; LDTR (LDT selector) + dw 0000 ; (padding) +ll3_GS dw 0000 ; GS + dw 0000 ; (padding) +ll3_FS dw 0000 ; FS + dw 0000 ; (padding) +ll3_DS dw 0000 ; DS + dw 0000 ; (padding) +ll3_SS dw 0000 ; SS + dw 0000 ; (padding) +ll3_CS dw 0000 ; CS + dw 0000 ; (padding) +ll3_ES dw 0000 ; ES + dw 0000 ; (padding) +; +; System table and segment descriptor caches +; +ll3_TSScache db size DescCache386 dup (00) +ll3_IDTcache db size DescCache386 dup (00) +ll3_GDTcache db size DescCache386 dup (00) +ll3_LDTcache db size DescCache386 dup (00) +ll3_GScache db size DescCache386 dup (00) +ll3_FScache db size DescCache386 dup (00) +ll3_DScache db size DescCache386 dup (00) +ll3_SScache db size DescCache386 dup (00) +ll3_CScache db size DescCache386 dup (00) +ll3_EScache db size DescCache386 dup (00) + +ll3_temps db 134h dup (00) ; padding for internal temps + +LoadAllBuf386 ends + +.list ; end of LOADALL.INC diff --git a/v4.0/src/MEMM/MEMM/MACH_ID.INC b/v4.0/src/MEMM/MEMM/MACH_ID.INC new file mode 100644 index 0000000..ba217cb --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MACH_ID.INC @@ -0,0 +1,38 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: MACH_ID.INC - include for Machine ID types +; +; Version: 0.03 +; +; Date: April 9, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 04/09/86 Original +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +; STANDARD ROM BIOS MACHINE TYPES used in ROM_BIOS_Machine_ID + +RBMI_PC equ 0FFh +RBMI_PCXT equ 0FEh +RBMI_PCjr equ 0FDh +RBMI_PCAT equ 0FCh +RBMI_PCConvertible equ 0F9h +RBMI_Sys80 equ 0F8h +RBMI_CompaqPortable equ 000h diff --git a/v4.0/src/MEMM/MEMM/MAKEFILE b/v4.0/src/MEMM/MEMM/MAKEFILE new file mode 100644 index 0000000..9f1a77b --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MAKEFILE @@ -0,0 +1,343 @@ +#****************************************************************************** +# title MAKEFILE - MEMM build file +#****************************************************************************** +# +# (C) Copyright MICROSOFT Corp. 1986 +# +# Title: MEMM - MICROSOFT Expanded Memory Manager 386 +# +# Module: MAKEFILE +# +# Version: 0.06 +# +# Date: May 12, 1986 +# +# Author: +# +#****************************************************************************** +# +# Change log: +# +# DATE REVISION DESCRIPTION +# -------- -------- ------------------------------------------------------- +# Original +# 05/12/86 B- Cleanup and segment reorganization +# 06/03/86 C- Added module for driver i/f +# 06/08/86 C- Merge in lastest code from MS +# 06/17/86 D- Added debug version. +# 06/28/86 0.02 Name change from MEMM386 to MEMM +# 07/01/86 0.03 Added MapDMA module. +# 07/11/86 0.05 Moved HIFLAG into global includes. +# +#****************************************************************************** +# +# Functional Description: +# +# This file assembles and links +# (1) EMM386.EXE - Production version of EMM386 driver +# (2) EMM386.COM - Production version of EMM386 utility +# (3) EMM386D.EXE - Debug (Internal) version of EMM386 driver +# +#****************************************************************************** + +#****************************************************************************** +# R U L E S and M A C R O S +#****************************************************************************** +.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 +#ASM = c:\bin\masm400 +#ASM = masm400 +ASM = masm +AFLAGS = -Mx -t -DI386 -DNoBugMode $(HIFLAG) +ADFLAGS = -Mx -t -DI386 $(HIFLAG) +AINC = -i..\emm + +# Defines for C Compiler +C = cl +CFLAGS =/AS /G2 /Oat /Gs /Ze /Zl /Fc /c + +# Definitions for linker for old style .exe files +#LINK = c:\bin\link +#LINK = link +LINK = link +LFLAGS = /NOI + +# Definitions for .COM generation +CONVERT = c:\dos\exe2bin +#CONVERT = exe2bin + +# Rules for generating object and linker response and definition files +.asm.obj: + $(ASM) $(AFLAGS) $(AINC) -p $*.asm; + +.asm.lst: + $(ASM) -l -n $(AFLAGS) $(AINC) -p $*.asm; + +#****************************************************************************** +# List of include files required +#****************************************************************************** +MEMMINC = ascii_sm.equ driver.equ pic_def.equ romstruc.equ romxbios.equ \ + desc.inc elim.inc emm386.inc instr386.inc kbd.inc loadall.inc \ + oemdep.inc page.inc vdmseg.inc vdmsel.inc vm386.inc mach_id.inc + + +#****************************************************************************** +# List of object files required +#****************************************************************************** + +MEMMOBJ = memm386.obj elimfunc.obj init.obj allocmem.obj ppage.obj emmmes.obj \ + inittab.obj memmonf.obj rom_srch.obj i286.obj trapdef.obj \ + i386.obj tabdef.obj vmtrap.obj vminst.obj elimtrap.obj \ + vminit.obj moveb.obj em286ll.obj em386ll.obj retreal.obj \ + rrtrap.obj vdminit.obj initepg.obj errhndlr.obj maplin.obj \ + ekbd.obj util.obj initdeb.obj emm.obj emminit.obj mapdma.obj \ + iotrap.obj a20trap.obj oemproc.obj m_state.obj \ + shiphi.obj extpool.obj + +COMOBJ = memmcom.obj memmonf.obj + +BUGOBJ = memm386.obj elimfunc.obj init.obj allocmem.obj ppage.obj emmmes.obj \ + inittab.obj memmonf.obj rom_srch.obj i286.obj trapdef.obj \ + i386.obj tabdefD.obj vmtrapD.obj vminstD.obj elimtrap.obj \ + vminit.obj moveb.obj em286ll.obj em386ll.obj retreal.obj \ + rrtrap.obj vdminitD.obj initepg.obj errhndlr.obj maplin.obj \ + ekbd.obj util.obj initdebD.obj emmD.obj emminit.obj mapdma.obj \ + iotrap.obj a20trap.obj oemproc.obj kbd.obj print.obj m_state.obj + +#****************************************************************************** +# List of libraries required +#****************************************************************************** + +MEMMLIBS = ..\emm\emmlib.lib + +BUGLIBS = ..\deb386\buglib.lib ..\emm\emmlib.lib + +#****************************************************************************** +# Listing files +#****************************************************************************** +MEMMLST = memm386.lst elimfunc.lst init.lst ppage.lst allocmem.lst emmmes.lst \ + inittab.lst memmonf.lst rom_srch.lst i286.lst trapdef.obj \ + i386.lst tabdef.lst vmtrap.lst vminst.lst elimtrap.lst \ + vminit.lst moveb.lst em286ll.lst em386ll.lst retreal.lst \ + rrtrap.lst vdminit.lst initepg.lst errhndlr.lst maplin.lst \ + ekbd.lst util.lst initdeb.lst emm.lst emminit.lst mapdma.lst \ + iotrap.lst a20trap.lst memminc.lst oemproc.lst shiphi.lst \ + extpool.lst + +COMLST = memmcom.lst memmonf.lst + +BUGLST = memm386.lst elimfunc.lst init.lst allocmem.lst ppage.lst emmmes.lst \ + inittab.lst memmonf.lst rom_srch.lst i286.lst trapdef.lst \ + i386.lst tabdefD.lst vmtrapD.lst vminstD.lst elimtrap.lst \ + vminit.lst moveb.lst em286ll.lst em386ll.lst retreal.lst \ + rrtrap.lst vdminitD.lst initepg.lst errhndlr.lst maplin.lst \ + ekbd.lst util.lst initdebD.lst emmD.lst emminit.lst mapdma.lst \ + iotrap.lst a20trap.lst kbd.lst emmincD.lst oemproc.lst + + +#****************************************************************************** +# MEMM targets +#****************************************************************************** +#emm386: emm386.exe emm386.com emm386d.exe +emm386: emm386.exe + +# production version of EMM386 device driver +# +emm386.exe: $(MEMMOBJ) $(MEMMLIBS) emm386.lnk + $(LINK) $(LFLAGS) @emm386.lnk + del emm386.sys + ren emm386.exe emm386.sys + +# EMM386.COM utility +# +#emm386.com: $(COMOBJ) emmcom.lnk +# $(LINK) $(LFLAGS) @emmcom.lnk +# $(CONVERT) emmcom.exe emm386.com + +# debug version of EMM386 driver +# +#emm386d.exe: $(BUGOBJ) $(BUGLIBS) emm386d.lnk +# $(LINK) $(LFLAGS) @emm386d.lnk + +#****************************************************************************** +# EMM386 driver i/f modules +#****************************************************************************** + +memm386.obj: memm386.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +memm386.lst: memm386.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +elimfunc.obj: elimfunc.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +elimfunc.lst: elimfunc.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +init.obj: init.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +init.lst: init.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +allocmem.obj: allocmem.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +allocmem.lst: allocmem.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +rom_srch.obj: rom_srch.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +rom_srch.lst: rom_srch.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +inittab.obj inittab.lst: inittab.asm $(MEMMINC) + +emmmes.obj emmmes.lst: emmmes.asm $(MEMMINC) + +extpool.obj extpool.lst: extpool.asm $(MEMMINC) + +shiphi.obj shiphi.lst: shiphi.asm $(MEMMINC) + +m_state.obj m_state.lst: m_state.asm $(MEMMINC) + +ppage.obj ppage.lst: ppage.asm $(MEMMINC) ..\emm\emmdef.inc + +#****************************************************************************** +# VDM modules +#****************************************************************************** + +vdminit.obj vdminit.lst: vdminit.asm $(MEMMINC) + +i286.obj i286.lst: i286.asm $(MEMMINC) + +i386.obj i386.lst: i386.asm $(MEMMINC) + +trapdef.obj trapdef.lst: trapdef.asm $(MEMMINC) + +tabdef.obj tabdef.lst: tabdef.asm $(MEMMINC) + +vmtrap.obj vmtrap.lst: vmtrap.asm $(MEMMINC) + +vminst.obj vminst.lst: vminst.asm $(MEMMINC) + +elimtrap.obj: elimtrap.asm $(MEMMINC) ..\emm\emmdef.inc + $(ASM) $(AFLAGS) $(AINC) $*.asm; +elimtrap.lst: elimtrap.asm $(MEMMINC) ..\emm\emmdef.inc + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +iotrap.obj iotrap.lst: iotrap.asm $(MEMMINC) + +initepg.obj: initepg.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +initepg.lst: initepg.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +vminit.obj vminit.lst: vminit.asm $(MEMMINC) + +em286ll.obj em286ll.lst: em286ll.asm $(MEMMINC) + +em386ll.obj em386ll.lst: em386ll.asm $(MEMMINC) + +moveb.obj: moveb.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +moveb.lst: moveb.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +util.obj: util.asm $(MEMMINC) + $(ASM) $(AFLAGS) $(AINC) $*.asm; +util.lst: util.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +maplin.obj maplin.lst: maplin.asm $(MEMMINC) + +a20trap.obj a20trap.lst: a20trap.asm $(MEMMINC) + +oemproc.obj oemproc.lst: oemproc.asm $(MEMMINC) + +rrtrap.obj rrtrap.lst: rrtrap.asm $(MEMMINC) + +retreal.obj retreal.lst: retreal.asm $(MEMMINC) + +errhndlr.obj errhndlr.lst: errhndlr.asm $(MEMMINC) + +ekbd.obj ekbd.lst: ekbd.asm $(MEMMINC) + +initdeb.obj initdeb.lst: initdeb.asm $(MEMMINC) + +emminit.obj emminit.lst: emminit.asm $(MEMMINC) + +emm.obj emm.lst: emm.asm $(MEMMINC) + +mapdma.obj mapdma.lst: mapdma.c + $(C) /ASw /G2 /Oat /Gs /Ze /Zl /Fc /c mapdma.c + +memminc.lst: memminc.asm $(MEMMINC) + $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +#****************************************************************************** +# debug modules +#****************************************************************************** + +#tabdefD.obj: tabdef.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) tabdef.asm,tabdefD.obj; +#tabdefD.lst: tabdef.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) tabdef.asm,tabdefD.obj,tabdefD.lst; +# +#vminstD.obj: vminst.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) vminst.asm,vminstD.obj; +#vminstD.lst: vminst.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) vminst.asm,vminstD.obj,vminstD.lst; + +#vmtrapD.obj: vmtrap.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) vmtrap.asm,vmtrapD.obj; +#vmtrapD.lst: vmtrap.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) vmtrap.asm,vmtrapD.obj,vmtrapD.lst; +# +#vdminitD.obj: vdminit.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) vdminit.asm,vdminitD.obj; +#vdminitD.lst: vdminit.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) vdminit.asm,vdminitD.obj,vdminitD.lst; + +#initdebD.obj: initdeb.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) initdeb.asm,initdebD.obj; +#initdebD.lst: initdeb.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) initdeb.asm,initdebD.obj,initdebD.lst; + +#emmD.obj: emm.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) emm.asm,emmD.obj; +#emmD.lst: emm.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) emm.asm,emmD.obj,emmD.lst; + +#kbd.obj kbd.lst: kbd.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) -p $*.asm; + +#print.obj print.lst: print.asm $(MEMMINC) +# $(ASM) $(ADFLAGS) $(AINC) -p $*.asm; + +#memmincD.lst: memminc.asm $(MEMMINC) +# $(ASM) -l -n $(ADFLAGS) $(AINC) memminc.asm,memmincD.obj,memmincD.lst; + +#****************************************************************************** +# EMM386.COM modules +#****************************************************************************** + +#memmcom.obj: memmcom.asm +# $(ASM) $(AFLAGS) $(AINC) $*.asm; +#memmcom.lst: memmcom.asm +# $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + +#memmonf.obj: memmonf.asm memm_msg.inc +# $(ASM) $(AFLAGS) $(AINC) $*.asm; +#memmonf.lst: memmonf.asm memm_msg.inc +# $(ASM) -l -n $(AFLAGS) $(AINC) $*.asm; + + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/MAPDMA.ASM b/v4.0/src/MEMM/MEMM/MAPDMA.ASM new file mode 100644 index 0000000..c1e1f4f --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MAPDMA.ASM @@ -0,0 +1,633 @@ + + +page 58,132 +;****************************************************************************** + title MapDMA - Ensure all DMA transfers are physically contiguous +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: MapDMA +; +; Version: 0.04 +; +; Date: June 18,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/18/86 Original +; 07/02/86 0.03 Added check for ECX = 0 +; 07/02/86 0.03 MapLinear added to set_selector +; 07/06/86 0.04 Changed _pft386 to ptr to _pft386 array +; 07/06/86 0.04 Changed assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; +; This module ensures that EMM pages accessed by a DMA transfer (within +; the EMM Page Frame) are physically contiguous in memory. This is accomplished +; by physically relocating entire EMM pages so that all of the pages participating +; in the DMA transfer are adjacent. As a first pass, pages that need to be +; relocated will always be moved to the base address of extended memory (or +; possibly hi memory if that option is selected). A four word array (DMA_Pages) +; initialized by InitEPG will contain the actual 32 bit physical address of +; the first four physical EMM page locations. Although this will decrease +; the time necessary to search for potential relocation candidates, it could +; also result in the relocation of all pages when a fewer number might suffice +; (given a more elegant mapping scheme). +; +; Some transfers that will NOT require remapping are: +; 1. The DMA transfer is entirely outside the EMM Page Frame +; 2. The DMA transfer is entirely within one Page Frame Window +; 3. The DMA transfer spans more than one Page Frame Window, but +; the EMM pages currently residing there are already contiguous +; 4. See number 4 below +; +; Some transfers that will result in an exception are: +; 1. The DMA transfer spans more than one Page Frame Window, where +; at least one (but not all) of the windows is currently unmapped. +; 2. The DMA transfer spans more than one Page Frame Window, with +; the same EMM page residing in more than one of the windows +; 3. The DMA transfer spans more than one Page Frame Window, but there +; is physically not enough contiguous memory in which to locate the +; requested EMM Pages. (This could occur in the model where both +; extended memory and hi memory combine to form the EMM pool) +; 4. The DMA transfer includes memory outside the Page Frame, AND +; INSIDE the Page Frame (unless the Page Frame Windows are currently +; unmapped, in which case no relocation is necessary) +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public MapDMA + public DMA_Pages + public DMA_PAGE_COUNT + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + include page.inc + include instr386.inc + include vm386.inc + include emmdef.inc +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +ABS0 segment use16 at 0000h +ABS0 ends + +_DATA segment + +extrn _page_frame_base:dword ; Page Table Entry pointers for windows 0-3 +extrn _pft386:word ; ptr to array of Page Table entries +;extrn _current_map:byte ; current mapping register values +extrn PF_Base:word ; Base addr of page frame +extrn _total_pages:word ; total number of EMM pages +extrn Page_Dir:word + +xfer_map dw 0 ; map of windows participating in DMA xfer +_DATA ends + +_TEXT segment + + extrn ErrHndlr:near + extrn MapLinear:near + +_TEXT ends + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +_DATA segment + +; +; DMA_Pages - EMM Pages for DMA relocation. Each is an index into pft386. +; To access actual entry in pft386 you need to multiply index by 4. +; If eight contingous 16k EMM pages are not available - the unavailable +; entries are left at NULL_PAGE. +; This array should be initialized at boot time. +; +DMA_Pages dw 8 dup (NULL_PAGE) ; null for start +DMA_PAGE_COUNT dw 0 ; number of above initialised + +_DATA ends + +;------------------------------------------------------------------------------ +_TEXT segment + + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP + page +;****************************************************************************** +; MapDMA - Relocate (if necessary) EMM pages to ensure that a DMA transfer +; is contiguous +; +; ENTRY: Protected Mode Ring 0 +; EAX = linear base address of DMA transfer +; ECX = byte count of transfer +; DGROUP:[_pft386] = ptr to dword array of ptrs for EMM Pages +; DGROUP:[DMA_Pages] = array of EMM page addresses in 1st 64k (used for +; relocating pages to contiguous physical memory) +; +; EXIT: Protected mode Ring 0 +; EAX = physical base address for DMA transfer +; DGROUP:_pft386[] = modified to reflect relocation of EMM pages +; Page Table Entries modified to reflect relocation. +; CY = CLEAR if exit address = entry address +; CY = SET if exit address <> entry address (mapping was necessary) +; +; USED: EAX +; Flags +; STACK: +;****************************************************************************** +MapDMA proc near +; + PUSH_EBX + PUSH_EAX ; save original address + PUSH_ECX + PUSH_EDX + PUSH_EDI + PUSH_ESI + push es +; + cld +; +; check for ECX = 0 +; + jecxz nomap1 ; nomap out of jmp range + jmp short mDMA_domap +nomap1: + jmp nomap +; +; As a quick first check, let's see if this transfer is any where near the PF +; +mDMA_domap: + mov ebx,eax ; get address + shr ebx,16 ; get rid of 64k + mov dx,[PF_Base] ; base address of Page Frame div 4 + mov di,dx ; save it + shr dx,12 ; divide by 64k + cmp bx,dx ; q: is it in PF? + jb nomap ; n: no mapping necessary + add di,0fffh ; plus 64k div 4 for end of PF + shr di,12 ; divide by 64k + cmp bx,di ; q: before end of PF? + ja nomap ; n: no mapping necessary +; + push ax ; save lower 16 bits of addr + mov ebx,4000h ; window size +; +; build a map of windows used in this transfer +; + mov [xfer_map],0 ; zero to start with + dec ecx ; stop at last byte +lloop: + call chk_loc ; mark this guy's location in the map + or ecx,ecx ; q: done? + jz chk_done ; y + cmp ecx,ebx ; n: q: is there a whole window left? + jae full_wind ; y: skip the adjustment + mov bx,cx ; n: just check what's left +full_wind: + sub ecx,ebx ; adjust count by window size + add ax,bx ; and base addr (let it wrap) + jmp lloop ; do the next one +chk_done: + pop ax ; restore base addr of transfer + shl [xfer_map],1 ; q: is the transfer outside the PF? + jnc in_PF ; n: entirely within Page Frame +; +; At least part of the transfer involves an area outside the Page Frame. +; This is ok as long as all parts inside the Page Frame are currently unmapped. +; + mov cx,[xfer_map] ; get the map values + xor si,si ; set up to check all windows + xor edx,edx ; clean out high bits + mov dx,[PF_Base] ; dx = address of window 0 + shl edx,4 ; make it 32 bits +mloop1: + shl cx,1 ; q: is this window involved? + jnc not_inv ; n: not involved but still more to check + call IsMapped ; q: is this page mapped? + jne excp ; y: exception (can't handle it) +not_inv: + add edx, 4000h ; n: update address of window + add si,4 ; and _page_frame_base index + or cx,cx ; q: any more to check? + jnz mloop1 ; y: check the next window +; +nomap: jmp DMA_nomap ; don't need to relocate +; +excp: jmp DMA_excp ; exception (can't deal with this) +; +; The DMA transfer is entirely within the Page Frame area. If the +; physical location of the EMM pages (mapped into the windows participating +; in the DMA transfer) are already contiguous, then don't do anything. +; Otherwise, relocate them to the base area. +; +; eax >= [PF_Base] = linear base address of xfer +; +in_PF: + mov bx,[xfer_map] ; get a copy of the map + shr bx,4 ; duplicate on the end + or [xfer_map],bx ; ... for wraparound + op32 + mov cx,ax ; ecx = base addr of xfer + op32 + shr cx,4 ; paragraph form + sub cx,[PF_Base] + shr cx,10 ; cx = starting window of transfer + shl [xfer_map],cl ; position on 1st window of transfer + and [xfer_map],0f7ffh ; only 1st 4 windows are valid + shl [xfer_map],1 ; we know there's at least one + or [xfer_map],cx ; save starting window number + mov bx,cx ; bx = starting window + shl bx,2 ; bx = double word index + mov cx,[xfer_map] ; get map back + les di,_page_frame_base[bx] ; es:di = page table pointer for window bx + and ax,3fffh ; get lower 14 bits + push ax ; save lower 14 bits of starting addr + op32 + mov ax,es:[di] ; get page table entry + and ax,0f000h ; get rid of lower 12 bits + push_eax ; save physical address +; +; bx = window number to check for contiguity +; eax = physical address of EMM page mapped into previous window +; cx = bit map of windows participating in the transfer +; +c_chk: + shl cx,1 ; q: is the next window involved? + jnc DMA_addr ; n: no need to check any more + add bx,4 ; next window + and bx,0fh ; mod 16 + add ax,4000h ; next physically contiguous window + les di,_page_frame_base[bx] ; es:di = page table pointer for window bx + op32 + mov dx,es:[di] ; get page table entry + and dx,0f000h ; get rid of lower 12 bits + op32 + cmp ax,dx ; q: contiguous? + je c_chk ; y: check next window +; + jmp DMA_reloc ; They were not contiguous, must relocate +DMA_addr: + pop_eax ; top part of actual address + pop dx ; get second half of actual address + or ax,dx ; form real address + jmp DMA_nomap ; don't need to map +; +; Relocate EMM pages mapped into the windows starting with the +; low order bits of [xfer_map], for as many high bits of [xfer_map]. +; The lower 14 bits of original address are still on the stack +; +DMA_reloc: + pop_eax ; top part of actual address + mov bx,[xfer_map] ; get map + mov cx,bx ; copy it + and bx,3 ; bx = starting window number + xor di,di ; di = index into DMA_Pages +reloc_loop: + mov si,12 ; board index for _current_map + push cx ; save window map + mov cx,4 ; 4 boards +bloop: +; WE NEED TO WORK ON THE DMA MORE +; BUT int the mean time, ignore _current_map (Paul Chan) +; mov dl,_current_map[bx+si] ; get mapping register value + shl dl,1 ; q: is it mapped? + jnc next_board ; n: try next board + mov dh,cl ; y: dh = board number + dec dh ; board is zero relative + shr dx,1 ; dx = EMM page number + cmp dx,[_total_pages] ; q: is this page in range? + jb found_page ; y: go relocate it +next_board: ; n: try next board + sub si,4 ; update index to _current_map + loop bloop ; do another +; +; If we ever get here, we've got a problem in the data structures, or +; in the previous couple of hundred lines since we couldn't seem to locate +; any pages occupying window bx (which should have generated an exception +; long ago). In either case, we might just as well call it an exception. +excp2: jmp DMA_excp ; don't know what else to do +; +; At this point we have found the EMM page (= dx) occupying window bx. +; di is the index into DMA_Pages that tells us the physical address of this +; particular relocation area. Now we need to run through _pft386 and find +; this address so we can swap him with page dx. If DMA_Pages contains -1, +; then we just don't have the physically contiguous memory to get the job done. +; +found_page: + push di ; save di + op32 + mov ax,DMA_Pages[di] ; get addr of relocation area + op32 + or ax,ax ; q: -1? + js excp2 ; y: not enough contig memory + mov cx,[_total_pages] ; number of entries in _pft386 + mov si,-4 ; index into _pft386 + add si,[_pft386] ; si = ptr for _pft386 array +floop: + add si,4 ; point to next entry + op32 + mov di,[si] ; get pft entry + and di,0f000h ; get rid of low 12 bits + op32 + cmp di,ax ; q: did we find who's there? + loopne floop ; n: keep looking + jne excp2 ; whoops, nobody was using it +; +; si = ptr to EMM page currently using our relocation area. +; Swap it with EMM page # dx +; + mov di,dx ; page number in window + shl di,2 ; offset for _pft386 + add di,[_pft386] ; di -> EMM page#dx entry + cmp di,si ; q: was it us all along? + je no_swap ; y: don't need to move it + op32 + mov dx,[di] ; PTE for this page + and dx,0f000h ; get rid of low 12 bits +; +; DS:SI -> relocation page entry in _pft386 +; DS:DI -> EMM page # dx entry in _pft386 +; check to see if we have already relocated this guy once. If so, that +; implies that the same EMM page is mapped into more than one window. +; Since there is no way (without scratch buffers) to make that contiguous, +; we will just abort. +; + op32 + cmp dx,[DMA_Pages] ; q: have we already relocated it? + jb no_dup ; n: ok + op32 + cmp dx,ax ; q: is it in the relocation area? + jb excp2 ; y: sorry +no_dup: + op32 + and [si],0fffh ; preserve his 12 bits + dw 0 + op32 + or [si],dx ; move in his new address + op32 + and [di],0fffh ; now do the same thing + dw 0 ; for the page in the window + op32 + or [di],ax ; fix up his address +; +; swap pages residing at addresses eax and edx +; + push_eax ; save address in window + push ds + mov di,MBSRC_GSEL ; source selector + call set_selector ; set to address eax + mov es,di + mov di,MBTAR_GSEL ; destination selector + op32 + mov ax,dx ; destination + call set_selector ; set up selector + mov ds,di + mov cx,1000h ; 16k bytes (4 at a time) + xor di,di ; initialize index +sloop: + op32 + mov ax,es:[di] ; get a word from dest. + op32 + xchg ax,ds:[di] ; swap with source + op32 + stosw ; store in dest. + loop sloop ; do the next one +; + pop ds + pop_eax ; restore physical address + +no_swap: + + + pop di ; index into DMA_Pages + add di,4 ; update index + pop cx ; window map + inc bx ; next window number + and bx,3 ; mod 4 + shl cx,1 ; q: any left? + jnc fix_pte ; n: done relocating + jmp reloc_loop ; y: relocate the next page +fix_pte: +; +; Now set all 4 entries in page table. Rather than try to figure out exactly +; which entries in here have changed, we will reset all entries shown as +; being "mapped" by _current_map. Unmapped entries shouldn't have changed. +; + mov cx,15 ; start at last entry +ploop: + mov si,cx ; copy index +; mov bl,_current_map[si] ; get current_map entry + shl bl,1 ; q: is it mapped? + jnc pte_not_mapped ; n: try next + mov bh,cl ; copy index number + shr bh,2 ; get board number + shr bx,1 ; bx = emm page number + cmp bx,[_total_pages] ; q: in range? + jae pte_not_mapped ; n: try next + shl bx,2 ; y: index into _pft386 + add bx,[_pft386] ; ptr into _pft386 + op32 + mov ax,[bx] ; y: get pte value + and ax,0f000h ; get rid of lower 12 bits + mov si,cx ; get index number + and si,3 ; get window number + shl si,2 ; 32 bit index + les di,_page_frame_base[si] ; pointer to page table entry + or ax,P_AVAIL ; set access bits + op32 + stosw ; set 1st Page Table Entry + + add_eax_ 1000h ; 2nd 386 page + op32 + stosw ; set 2nd Page Table Entry + + add_eax_ 1000h ; 3rd 386 page + op32 + stosw ; set 3rd Page Table Entry + + add_eax_ 1000h ; 4th 386 page + op32 + stosw ; set 4th Page Table Entry +pte_not_mapped: + dec cx ; q: done with _current_map? + jns ploop ; n: keep going + +; +; reload CR3 to flush TLB +; + db 66h + mov ax,[Page_Dir] ; mov EAX,dword ptr [Page_Dir] + db 0Fh,22h,18h ; mov CR3,EAX + op32 + mov ax,[DMA_Pages] ; get physical address to return + pop dx ; don't forget about the lower 14 bits + or ax,dx +; +; eax = physical address for DMA transfer +; +DMA_nomap: + pop es + POP_ESI + POP_EDI + POP_EDX + POP_ECX + POP_EBX ; get original eax + clc ; assume they're the same + OP32 + cmp ax,bx ; q: did we have to map? + je cy_noset ; n: don't set carry + stc ; y: set carry +cy_noset: + POP_EBX +; + ret +DMA_excp: + mov ax,ExcpErr + mov bx,ErrDMA + jmp ErrHndlr ; don't come back + +MapDMA endp + + + page +;****************************************************************************** +; IsMapped - Check whether or not a window is unmapped +; +; ENTRY: Protected Mode Ring 0 +; si = window number * 4 +; edx = physical address of Page Frame Window +; DGROUP:[_page_frame_base] = array of ptrs to page table entries +; +; EXIT: Protected mode Ring 0 +; ZF = unmapped +; NZF= mapped +; +; USED: di,ebx,es +; Flags +; STACK: +;****************************************************************************** +isMapped proc near + les di,_page_frame_base[si] ; es:di = addr of page table entry + op32 + mov bx,es:[di] ; ebx = page table entry for window + and bx,0f000h ; mask off low order 12 bits + op32 + cmp bx,dx ; q: is it mapped to itself (unmapped)? + ret +isMapped endp + + + page +;****************************************************************************** +; chk_loc - Check the location of a given address and update map accordingly +; +; ENTRY: Protected Mode Ring 0 +; eax = physical address to check +; DGROUP:[xfer_map] = map of addresses used in this transfer +; bit 16 indicates an address outside the PF +; bits 15-12 correspond to windows 0-3 resp. +; +; EXIT: Protected mode Ring 0 +; DGROUP:[xfer_map] = updated as necessary +; +; USED: none +; Flags +; STACK: +;****************************************************************************** +chk_loc proc near + push_eax ; save address + push cx +; + mov ch,80h ; set high bit (outside indicator) + op32 + shr ax,4 ; put in paragraph form + sub ax,[PF_Base] ; make it relative to base of Page Frame + jb outside ; outside of page frame + op32 + shr ax,10 ; ax = window number + cmp_eax_ 3 ; q: inside Page Frame? + ja outside ; n: outside + mov cl,al ; + inc cl ; skip over outside bit + shr ch,cl +outside: + xor cl,cl ; clear lower byte + or [xfer_map],cx +; + pop cx + pop_eax + ret +chk_loc endp + page +;****************************************************************************** +; set_selector - set up a selector address/attrib +; +; ENTRY: EAX = address for GDT selector +; DI = GDT selector +; EXIT: selector at ES:DI is writeable data segment,64k long and points +; to desired address. +; +;****************************************************************************** +set_selector proc near +; + PUSH_EAX + push di + push es +; + call MapLinear +; + and di,NOT 07h ; just in case... GDT entry + push GDTD_GSEL + pop es ; ES:DI -> selector entry +; + mov es:[di+2],ax ; low word of base address + OP32 + shr ax,16 ; AX = high word of address + mov es:[di+4],al ; low byte of high word of address + xor al,al ; clear limit/G bit + mov es:[di+6],ax ; set high byte of high word of addr + ; and high nibble of limit/G bit +; + mov ax,0FFFFh + mov es:[di],ax ; set limit to 64k +; + mov al,D_DATA0 ; writeable DATA seg / ring 0 + mov es:[di+5],al +; + pop es + pop di + POP_EAX + ret +; +set_selector endp + +_TEXT ends ; end of segment +; + end ; end of module + diff --git a/v4.0/src/MEMM/MEMM/MAPDMA.C b/v4.0/src/MEMM/MEMM/MAPDMA.C new file mode 100644 index 0000000..7aae10d --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MAPDMA.C @@ -0,0 +1,425 @@ + + +/* MAPDMA.C - Ensures DMA Xfer area is physically contiguous. Swaps pages + * if necessary. + * + * Date Author Comments + 8/12/88 JHB updated comments, checking for sufficient pages + available in DMA_Pages[] before remappping + + 8/18/88 JHB if incoming parameters appear to be wrong or + if any unmapped page found in the transfer area assume + the Address and Count registers do not have valid values + and hence return without swapping pages. + Removed IFDEF DEBUG code + */ + +#define HEX4K 0x1000 +#define HEX16K 0x4000L +#define HEX64K 0x10000 +#define HEX128K 0x20000 +#define HEX256K 0x40000L +#define HEX640K 0xA0000L +#define HEX1MB 0x100000L + +#define ALIGN128K ~0x1FFFFL +#define ALIGN64K ~0x0FFFFL +#define ALIGN16K ~0x03FFFL + +#define MAX_PHYS_PAGES 40 + +/* macros + * PT(a) - pte from index a + * INDEX(a) - index from Linear Adr + * OFFSET(a) - offset from Linear Adr + * LIN2PHY(l) - Physical Adr from Linear Adr + * DosPhyPage - consider 16K pages from 0 to 1MB. Let Page at 256K be page 0. + * DOSPHYPAGE(a) - DosPhyPage for Adr in 1 MB range + * PFT(a) - pick up ith entry in pft386[] + */ + +#define PT(a) (GetPteFromIndex((a))) +#define INDEX(a) ((((long)a)>>12) & 0x3FF) +#define OFFSET(a) (((long)a) & 0xFFF) +#define LIN2PHY(l) ((PT(INDEX(l)) & ~0xFFFL)+(long)OFFSET(l)) +#define DOSPHYPAGE(a) (((a)>>14)-16) +#define PFT(a) (*(long *)(pft386+a)) +struct mappable_page { + unsigned short page_seg; /* segment of physical page */ + unsigned short physical_page; /* physical page number */ +}; + +/* Xlates DosPhyPage into an index in mappable_pages[]. */ +extern char EMM_MPindex[]; /* index from 4000H to 10000H in steps of 16K */ +extern struct mappable_page mappable_pages[]; +extern long *pft386; +extern unsigned DMA_Pages[]; +extern DMA_PAGE_COUNT; /* size of DMA_Pages[] */ +extern unsigned physical_page_count; + +/* routines imported from elimtrap.asm */ +extern long GetPte(); /* get a PT entry given index */ +extern SetPte(); /* set a PT entry */ +extern unsigned GetCRSEntry(); /* get CurRegSet entry for given EmmPhyPage */ +extern long GetDMALinAdr(); /* Get Linear Adr for the DMA buffer */ +extern Exchange16K(); /* exchange page contents */ +extern FatalError(); + +/* forward declarations */ +long GetPteFromIndex(); + +/* + * SwapDMAPages() + * FromAdr - DMA Xfer addr + * Len - Xfer length + * bXfer - 0 for byte transfer, 1 for word transfer + * + * Check whether the DMA Xfer area starting at FromAdr is contiguous in + * physical memory. If it isn't, make it contiguous by exchanging pages + * with the DMA buffer. + */ + +long SwapDMAPages(FromAdr, Len, bXfer) +long FromAdr, Len; +unsigned bXfer; +{ +unsigned Index, Offset, /* components of a PTE */ + n4KPages, /* # of 4K Pages involved in the DMA transfer */ + PhyPages[8], /* Emm Phy page numbers involved in the DMA transfer + atmost 8.*/ + DMAPageK, /* kth DMA Page - start exchanging pages from here */ + Page, MPIndex; + +long FromAdr16K, /* FromAdr rounded down to 16K boundary */ + FromAdr64_128K, /* FromAdr rounded down to 64/128K boundary */ + ToAdr, /* Last Byte for the DMA trasfer */ + ToAdr16K, /* ToAdr rounded down to 16K boundary */ + ExpectedAdr, + PgFrame, /* PgFrame Address */ + First64_128K_Adr, Last64_128K_Adr,/* First and Last 4K page aligned on a 64/128 boundary */ + Adr, PhyAdr, LinAdr; + +int i, j, k, bSwap, + n16KPages; /* # of 16K Pages involved in the DMA transfer */ + + + if (FromAdr < HEX256K || FromAdr >= HEX1MB) + return LIN2PHY(FromAdr); /* not in the EMM area */ + +/* Since the Address and count register are programmed a byte at a time + * they might have invalid values in them (because of left overs). + * If invalid parameters, i.e. Xfer area crosses 64K or 128K boundary,or count + * is invalid or the DMA Xfer area has unmapped pages - just return. + */ + if ((!bXfer && (FromAdr + Len) > ((FromAdr & ALIGN64K) + HEX64K)) || + (bXfer && (FromAdr + Len) > ((FromAdr & ALIGN128K) + HEX128K)) || + (!bXfer && Len > HEX64K) || (bXfer && Len > HEX128K)) + return FromAdr; /* assume DMA registers not programmed yet */ + +/* initialise PhyPages[] - unequal negative values */ + for (i = 0; i < 8; i++) + PhyPages[i] = -(i+1); + + +/* The DMA buffer is part of the Emm pool. + * Hence we can only swap pages which are 16K in size. Hence calculate + * n16KPages - # of 16K pages involved in the transfer. + + * ToAdr - Linear Address of the last byte where the DMA transfer + * is to take place + */ + ToAdr = FromAdr + Len - 1L; + FromAdr16K = FromAdr & ALIGN16K; + ToAdr16K = ToAdr & ALIGN16K; + n16KPages = ((ToAdr16K - FromAdr16K)>>14) + 1; /* (ToAdr16K-FromAdr16K)/HEX16K + 1 */ + +/* If any unmapped page in the transfer area - assume DMA registers not + * fully programmed yet + */ + for (i = 0, Adr = FromAdr16K; Adr <= ToAdr16K; Adr += HEX16K, i++) { + MPIndex = EMM_MPindex[DOSPHYPAGE(Adr)]; + if (MPIndex == -1) /* Adr not mappable */ + return FromAdr; + else { + PhyPages[i] = GetCRSEntry(mappable_pages[MPIndex].physical_page); + if (PhyPages[i] == -1) /* Adr not mapped currently */ + return FromAdr; + } + } + + for (j = 0; j < i; j++) { + Page = PhyPages[j]; + for (k = j+1; k < i; k++) { + if (PhyPages[k] == Page) + FatalError("SwapDMAPages : Two Emm pages mapped to same logical page in the xfer area"); + } + } + +/* No unmapped page in the transfer area. Assume the Address and count registers + * have meaningful values in them. + */ + Index = INDEX(FromAdr); + PgFrame = PT(Index) >> 12; + Offset = OFFSET(FromAdr); + PhyAdr = (((long)PgFrame) << 12) + Offset; + + if (Offset + Len <= HEX4K) /* within a page */ + return PhyAdr; + +/* calculate # of 4K pages involved in the DMA transfer */ + + n4KPages = ((Offset + Len)>>12) + 1; /* (Offset+Len)/4096K + 1 */ + if (((Offset + Len) % HEX4K) == 0) + n4KPages--; + +/* see if these n4KPages are physically contiguous */ + bSwap = 0; + for (i = 1; i < n4KPages; i++) { + if ((PT(Index + i)>>12) != (PgFrame + i)) { + bSwap = 1; + break; + } + } + +/* Suppose the Xfer area is physically contiguous. We may still need to swap + * pages with the DMA buffer if the physical pages straddle a 64K/128K boundary + * (the DMA will wrap around in this case). DOS would have tried to fix this + * but it would have split the Linear Address - this is of very little use. + * + * if (!bSwap && straddling 64/128K boundary) set bSwap; + */ + if (!bSwap) { /* the DMA Pages are contiguous, any straddling ? */ + if (!bXfer) { /* byte transfer */ + First64_128K_Adr = PT(Index) & ALIGN64K; + Last64_128K_Adr = PT(Index+n4KPages-1) & ALIGN64K; + } + else { /* word transfer */ + First64_128K_Adr = PT(Index) & ALIGN128K; + Last64_128K_Adr = PT(Index+n4KPages-1) & ALIGN128K; + } + + if (First64_128K_Adr != Last64_128K_Adr) + bSwap = 1; + } + + if (!bSwap) + return PhyAdr; + +/* The DMA transfer area is not contiguous. The DMA buffer is part of the Emm + * pool. Hence we can only swap pages which are 16K in size. n16KPages is the + * # of 16K pages involved in the transfer. + */ + +/* Round down FromAdr to 64/128K boundary */ + if (bXfer) /* word transfer ? */ + FromAdr64_128K = FromAdr & ALIGN128K; /* Align on 128K boundary */ + else + FromAdr64_128K = FromAdr & ALIGN64K; /* Align on 64K boundary */ + +/* Swap pages so that the DMA Xfer area is physically contiguous. + + | | | | + FromAdr ->| | | | + | | | | + | | | | + FromAdr16K ->| | - - - DMAPage[k] -->| | + | | | | + | | | | +FromAdr64_128k-| | DMAPage[0] -->| | + ---------- ---------- + + DMA transfer area starts at FromAdr. + Map kth DMA page to FromAdr16K and so on until all the transfer area is mapped + + */ + +/* Linear Adr of user page which has to be relocated */ + LinAdr = FromAdr16K; + +/* corresponding DMA Page - k value in the above figure */ + DMAPageK = (FromAdr16K - FromAdr64_128K) >> 14; + + ExpectedAdr = PFT(DMA_Pages[DMAPageK]); + + if (DMAPageK + n16KPages > DMA_PAGE_COUNT) + FatalError("Insufficient DMA pages in the DMA Buffer"); + + for (k = DMAPageK; k < DMAPageK + n16KPages; k++, LinAdr += HEX16K, + ExpectedAdr += HEX16K) { + /* Already mapped correctly ? */ + if (LIN2PHY(LinAdr) == ExpectedAdr) + continue; + /* Swap the 16K page(4 4K pages) at LinAdr with the kth DMA Page */ + SwapAPage(LinAdr, k); + } + + return LIN2PHY(FromAdr); +} + +/* Swap the 16K page(4 4K pages) at LinAdr with the kth DMA Page. + * Update the Emm Data Structures to reflect this remapping. + * Update the Page Table too. + */ +SwapAPage(LinAdr, k) +long LinAdr; +unsigned k; +{ +unsigned DosPhyPage, /* each page 16K in size, page at 256K is Page 0 */ + EmmPhyPage, /* Phy page numbering according to Emm */ + UserPFTIndex; /* index into pft386 for Emm phy page at LinAdr */ + +long DMAPhyAdr, DMALinAdr; +int i, j; + +/* Updating Emm data structures */ + +/* Find the pft386 entry for LinAdr */ + DosPhyPage = DOSPHYPAGE(LinAdr); /* Page at 256K is page zero */ + EmmPhyPage = mappable_pages[EMM_MPindex[DosPhyPage]].physical_page; + +/* get the CurRegSet entry for this physical page. */ + UserPFTIndex = GetCRSEntry(EmmPhyPage); + + if (UserPFTIndex == -1) + FatalError("Cannot find PFT386 entry for EMM page corresponding to LinAdr"); + +/* exchange pft386 entries at UserPFTIndex and DMA_Pages[k] */ + + DMAPhyAdr = PFT(DMA_Pages[k]); + PFT(DMA_Pages[k]) = PFT(UserPFTIndex); + PFT(UserPFTIndex) = DMAPhyAdr; + +/* Fix Page table entries . + * The contents of the user page and DMA buffer page are exchanged always. + * - because a mapping for this page may exist in a saved context, + * - can do a one way copy if the non-existence of such a mapping is detected + * by scanning emm_pages[]. Will optimize this later. 8/12/88 - JHB + * + * The PT entry for the user page has to be updated. + * There may or may not exist a PT entry for the DMA page. There exists + * an entry only if there exists a mapping in the CurRegSet. If there exists + * an entry it should be updated too. + */ + +/* Does PT Entry exist for the DMA buffer below 1 MB? */ + + for (i = 0; i < physical_page_count; i++) { + if (GetCRSEntry(i) == DMA_Pages[k]) + break; + } + + if (i == physical_page_count) { + /* No Phy page mapped to the DMA page - so no pte to be updated for DMA Page */ + Exchange16K(LinAdr, GetDMALinAdr(DMAPhyAdr)); + UpdateUserPTE(LinAdr, UserPFTIndex); + } + else { + /* ith EmmPhyPage mapped to DMA buffer + * Scan mappable_pages[] array and find the Linear address that maps to it. + */ + for (j = 0; j < MAX_PHYS_PAGES; j++) { + if (mappable_pages[j].physical_page == i) + break; + } + if (j == MAX_PHYS_PAGES) + FatalError(); /* invalid Phy page # - doesn't exist in mappable_pages[] */ + else + DMALinAdr = ((long )mappable_pages[j].page_seg) << 4; + + Exchange16K(LinAdr, DMALinAdr); + ExchangePTEs(LinAdr, DMALinAdr); + } + +/* UserPFTIndex is present in DMA_Pages[] we should exchange the entries in + * DMA_Pages[] */ + for (i = 0; i < DMA_PAGE_COUNT; i++) { + if (DMA_Pages[i] == UserPFTIndex) { + DMA_Pages[i] = DMA_Pages[k]; + break; + } + } + +/* Now, DMA_Pages[k] has a different index into the pft386[] array */ + DMA_Pages[k] = UserPFTIndex; +} + +/* Update PT entry for LinAdr to map to pft386[UserPFTIndex] */ +UpdateUserPTE(LinAdr, UserPFTIndex) +long LinAdr; +unsigned UserPFTIndex; +{ +unsigned index; +long pte; + + index = INDEX(LinAdr); + + pte = PFT(UserPFTIndex) & ~0xfff; /* Pg Frame Adr in 20 MSBs */ + + SetPteFromIndex(index, pte); + SetPteFromIndex(index+1, pte+HEX4K); + SetPteFromIndex(index+2, pte+HEX4K*2); + SetPteFromIndex(index+3, pte+HEX4K*3); +} + +/* exchange 4 ptes at LinAdr1 and LinAdr2 */ +ExchangePTEs(LinAdr1, LinAdr2) +long LinAdr1, LinAdr2; +{ +unsigned index1, index2; +long tPte; +int i; + + index1 = INDEX(LinAdr1); + index2 = INDEX(LinAdr2); + + for (i = 0; i < 4; i++) { + tPte = PT(index1+i); + SetPteFromIndex(index1+i, PT(index2+i)); + SetPteFromIndex(index2+i, tPte); + } +} + +/* sanity check on the index, and then call GetPte */ +long GetPteFromIndex(index) +unsigned index; +{ +unsigned i; +long PhyAdr; + + PhyAdr = ((long) index) << 12; + + if (PhyAdr < HEX256K || PhyAdr >= HEX1MB) + return (PhyAdr); + + i = EMM_MPindex[DOSPHYPAGE(PhyAdr)]; + + if (i != -1) + return GetPte(index); + else + return PhyAdr; +} + +/* sanity check on the index and then call SetPte */ +SetPteFromIndex(index, pte) +unsigned index; +long pte; +{ +unsigned i; +long PhyAdr; + + PhyAdr = ((long) index) << 12; + + if (PhyAdr < HEX256K || PhyAdr >= HEX1MB) + return; + + i = EMM_MPindex[DOSPHYPAGE(PhyAdr)]; + + if (i != -1) + return SetPte(index, pte); + else + return; +} + + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/MAPLIN.ASM b/v4.0/src/MEMM/MEMM/MAPLIN.ASM new file mode 100644 index 0000000..d37d9ac --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MAPLIN.ASM @@ -0,0 +1,172 @@ + + +page 58,132 +;****************************************************************************** + title MapLinear - map linear address according to page tables +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: MapLinear +; +; Version: 0.04 +; +; Date: June 2, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/08/86 Original +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/05/86 0.04 DiagByte moved to _DATA +; 07/06/86 0.04 changed assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; This routine in this module takes a "virtual" addresses specified by +; a virtual mode processs and "maps" it to the corresponding linear address +; according to the linear to physical mapping in the page tables. +; This file also contains a routine to do the inverse mapping. +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public MapLinear + public UnMapLinear +; + + page +;****************************************************************************** +; I N C L U D E F I L E S +;****************************************************************************** + + include vdmseg.inc + include vdmsel.inc + include instr386.inc + include oemdep.inc + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +;****************************************************************************** +; C O D E S E G M E N T +;****************************************************************************** +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP + page +;****************************************************************************** +; MapLinear - maps a linear address to it's "true" linear address. +; +; ENTRY: PROTECTED MODE ONLY +; EAX = 32 bit linear address +; +; EXIT: EAX = 32 bit "mapped" linear address +; +; USED: none. +; +; The page dir and table set up by this routine maps the linear +; addresses for Virtual mode programs into physical addresses using +; the following scheme. Note that "high" memory is mapped to the +; range starting at 16 Meg so that the page tables can be shorter. +; +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; 00110000h - 010FFFFFh 00100000h - 00FFFFFFh (top 15Meg of phys) +ifndef NOHIMEM +; 01010000h - 0101FFFFh xxxx0000h - xxxxFFFFh ("high" memory) +; xxxx is mapped by Map_Lin_OEM in OEMPROC module +endif +; +; True Linear is same as linear in our new mapping scheme. So except +; for the "high" memory we have the true linear returned being the same +; as linear. The new mapping is: +; +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; 00110000h - 00ffffffh 00110000h - 00ffffffh (top 15Meg of phys) +; 01000000h - 0100FFFFh xxxx0000h - xxxxFFFFh ("high" memory) +; xxxx is mapped by Map_Lin_OEM in OEMPROC module +; +;****************************************************************************** +MapLinear proc near +; + call Map_Lin_OEM ;Q: Special mapping done by OEM routines? + jc ML_Exit ; Y: AX = mapped address + ; N: Do standard mapping + +; +; the routine here is to be executed to get the true linear address. Since +; it is a 1 - 1 mapping we have no code here +; +ML_exit: + ret +; +MapLinear endp + + +;****************************************************************************** +; UnMapLinear - maps a "true" linear address to it's linear address. +; +; ENTRY: EAX = 32 bit "mapped" linear address +; +; EXIT: EAX = 32 bit linear address +; +; USED: none. +; +; The page dir and table set up maps the linear +; addresses for Virtual mode programs into physical addresses using +; the following scheme. +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; 00110000h - 010FFFFFh 00100000h - 00FFFFFFh (top 15Meg of phys) +ifndef NOHIMEM +; 01010000h - 0101FFFFh xxxx0000h - xxxxFFFFh (high memory) +; xxxx is mapped by UMap_Lin_OEM in OEMPROC module +endif +; +; Our new mapping scheme is: +; +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; 00110000h - 00ffffffh 00110000h - 00ffffffh (top 15Meg of phys) +; 01000000h - 0100FFFFh xxxx0000h - xxxxFFFFh ("high" memory) +; xxxx is mapped by Map_Lin_OEM in OEMPROC module +; +;****************************************************************************** +UnMapLinear proc near +; + cmp eax,01000000 ; + jb UML_mask ; N: chk for < 1 meg + call UMap_Lin_OEM ; Y: set EAX to physical address for diags + jmp short UML_exit + +UML_mask: +UML_exit: + ret +; +UnMapLinear endp + + +_TEXT ends + + end + diff --git a/v4.0/src/MEMM/MEMM/MEMM386.ASM b/v4.0/src/MEMM/MEMM/MEMM386.ASM new file mode 100644 index 0000000..d2b6d26 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MEMM386.ASM @@ -0,0 +1,561 @@ + + + page 58,132 +;****************************************************************************** + title MEMM386 - main module for MEMM +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: MEMM386 - main module +; +; Version: 0.04 +; +; Date: May 24,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 04/24/86 Original From EMML LIM driver. +; 06/26/86 0.02 Put CLD in Inst_Chk +; 06/28/86 0.02 Name change from MEMM386 to MEMM. +; 07/05/86 0.04 Changed segment to R_CODE +; 06/07/88 exclude VDISK header info's since we are +; using INT-15 method now (Paul Chan) +; 06/21/88 Removed VDISK stuff. +; +;****************************************************************************** +; Functional Description: +; MEMM is an Expanded Memory Manager which implements expanded memory +; on the MICROSOFT 386 machine. MEMM uses Virtual mode and paging on +; the 386 to make Extended memory useable as expanded memory. The are two +; basic functional parts of MEMM; the Virtual DOS Monitor (VDM) and the +; Expanded Memory Manager (EMM). VDM simulates the 386 Real mode under the +; 386 Virtual mode. EMM provides the software functionality for a EMM as +; described in the Lotus-Intel-Microsoft (LIM) specification for expanded +; memory. +; This module contains the Device Driver header, stategy, and interrupt +; routines required by a LIM standard EMM. +; This device driver is a .EXE file and may be invoked as a DOS utility +; program as well as loaded as a device driver. When it is loaded as a +; DOS utility, MEMM has three command line options: ON,OFF and AUTO. +; The OFF options disables MEMM and exits to MS-DOS in real mode. +; The ON option enables MEMM and exits to MS-DOS in virtual mode (only +; if the MEMM.EXE driver has been loaded). The AUTO option puts +; MEMM in "auto mode". In this mode, MEMM will enable and disable +; itself automatically, depending on accesses to the EMM functions. +; The general device driver CONFIG.SYS options are described below. +; +; Syntax: +; +; device=[d]:[]MEMM.EXE [SIZE] [Mx] [ON | OFF | AUTO] +; +; +; NOTE: SUNILP - See if we need the /X option for excluding segments from +; being mappable. This turned out to be quite useful in ps2emm and since +; here we are dealing with different hardware this option may turn out +; essential here**** WISH001 +; +; The following sections describe the optional arguments which the +; user may specify for MEMM.EXE at load time (in the CONFIG.SYS +; file). These arguments are placed after the device driver name +; in the CONFIG.SYS file. +; +; MEMM arguments in the CONFIG.SYS file must be separated by spaces +; or tabs. Arguments may appear in any order; however, any redundant +; or excessive instances are ignored and only the first valid instance +; of an argument is used. Invalid or extraneous arguments produce an +; error message. +; +; [SIZE] +; +; The argument SIZE is the amount of expanded memory desired in +; K bytes. The default amount of expanded memory, 256K, is available +; without using any extended memory. To use more than 256K of +; expanded memory, the 386 system must have extended memory. When +; If there is not enough memory available +; to provide SIZE kbytes of expanded memory, MEMM will adjust SIZE to +; provide as much expanded memory as possible. +; +; - The valid range for SIZE is 16K - 8192K. Value outside this range +; are converted to the default of 256K. +; +; - If SIZE is not a multiple of 16K (size of an EMM page), then SIZE +; is rounded down to the nearest multiple of 16K. +; +; [Mx] +; +; The argument [Mx] specifies the address of the 64k EMM page frame. +; This argument is optional since MEMM can choose an appropriate +; location for the page frame when it is loaded. To choose a location +; the 386 EMM driver scans memory addresses above video memory for +; an appropriate 64K address range for the EMM page frame. For a +; default page frame base address MEMM looks for option ROMs and +; RAM in the EMM addressing range and chooses a 64K slot of memory +; for the page frame which apparently does not confict with existing +; memory. The user may override the 386 EMM driver's choice by +; specifying the beginning address with the Mx argument. If the +; user specifies a page frame base address which conflicts with an +; option ROM or RAM, MEMM displays a warning message and uses the +; specified page frame base address. +; +; The following options are possible: +; Page Frame Base Address +; M1 => 0C0000 Hex +; M2 => 0C4000 Hex +; M3 => 0C8000 Hex +; M4 => 0CC000 Hex +; M5 => 0D0000 Hex +; +; [ ON | OFF | AUTO ] +; +; The argument [ON | OFF | AUTO] specifies the state of the 386 when +; MEMM returns to DOS after the driver INIT routine finishes. If this +; argument is ON, then MEMM returns to DOS in virtual mode and +; expanded memory is available. If this argument is OFF, then MEMM +; returns to DOS in real mode and expanded memory is not available +; until MEMM is turned ON. The default for this argument is AUTO +; mode. In AUTO mode, the MEMM.EXE device driver will exit to +; DOS in the OFF state; afterwards, MEMM will enable and disable +; itself automatically. In the AUTO mode, MEMM will be enabled +; only while the expanded memory manager is in use. +; +; +;****************************************************************************** +.lfcond +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** + +; +; R_CODE publics +; + public strategy + public interrupt + public MEMM_Entry + +; +; _TEXT publics +; + public ELIM_EXE ; .EXE execution entry point + public ELIM_link + public Inst_chk ; Check to see if MEMM already installed + public Inst_chk_f ; Far call version of above + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include driver.equ + include driver.str + include vdmseg.inc + +FALSE equ 0 +TRUE equ not FALSE + +MS_DOS equ 21h ; DOS interrupt +GET_PSP equ 62h ; get program segment prefix + +NULL EQU 0FFFFH ;Null address pointer + +dospsp_str struc + db 80h dup (?) +cmd_len db ? ; length of command line +cmd_line db ? ; commande line +dospsp_str ends + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +abs0 segment use16 at 0000h + + org 67h*4 ; EMM function interrupt +int67 dw ? ; offset of vector + dw ? ; segment of vector +abs0 ends + +LAST segment +extrn Init_MEMM386:far ; initializes VDM,EMM, and driver +LAST ends + +R_CODE segment +extrn ELIM_Entry:far ; general entry point for MEMM functions +R_CODE ends + +_TEXT segment +extrn onf_func:near ; perform on, off, or auto checking for elim.exe +_TEXT ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +;****************************************************************************** +; +; R_CODE Code Segment +; +;****************************************************************************** +; +R_CODE segment + assume cs:R_CODE, ds:R_CODE, es:R_CODE, ss:R_CODE + +Start: +;****************************************************************************** +; Device driver header +;****************************************************************************** +; + DW NULL ;Null segment address + DW NULL ;Null offset address + DW CHAR_DEV+IOCTL_SUP ;Attribute - Char + DW OFFSET STRATEGY ;Strategy routine entry + DW OFFSET INTERRUPT ;Interrupt routine entry + DB 'EMMXXXX0' ;Character device name +; +;****************************************************************************** +; GENERAL FUNCTIONS ENTRY POINT +; R_CODE:ELIM_Entry is a entry point for executing general MEMM +; functions. (e.g. ON, OFF function). +;****************************************************************************** +; +MEMM_Entry dw offset ELIM_Entry ; general entry point + +;****************************************************************************** +; MEMM signature +;****************************************************************************** +memmsig db 'MICROSOFT EXPANDED MEMORY MANAGER 386' +SIG_LENGTH equ (this byte - memmsig) + + page +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** + +; +; Define the command dispatch table for the driver functions +; +Cmd_Table LABEL NEAR + DW Init_Call ;0 - Initialization + DW Null_Exit ;1 - Media Check + DW Null_Exit ;2 - Get BPB + DW Null_Exit ;3 - IOCTL input + DW Null_Exit ;4 - Input (Destructive) + DW Null_Exit ;5 - No wait input + DW Null_Exit ;6 - Input status + DW Null_Exit ;7 - Input buffer flush + DW Null_Exit ;8 - Output (Write) + DW Null_Exit ;9 - Output with verify + DW Null_Exit ;A - Output status + DW Null_Exit ;B - Output buffer flush + DW Null_Exit ;C - IOCTL output +TBL_LENGTH EQU (THIS BYTE-CMD_TABLE)/2 ;Dispatch table length + + public ReqPtr +ReqPtr label dword ; dword ptr to Request Header +ReqOff dw 0 ; saved offset of Request Header +ReqSeg dw 0 ; saved segment of Request Header + + page +;****************************************************************************** +; Strategy - strategy routine for MEMM +; +; ENTRY: ES:BX = pointer to Request Header +; +; EXIT: CS:ReqOff, CS:ReqSeg - saved pointer to Request Header +; +; USED: none +; +;****************************************************************************** +Strategy proc far + mov CS:[ReqOff],bx ;Save header offset + mov CS:[ReqSeg],es ;Save header segment + ret +Strategy endp + +;****************************************************************************** +; Interrupt - device driver interrupt routine for MEMM +; +; ENTRY: CS:ReqPtr = pointer to request header. +; +; EXIT: Request completed. +; +; USED: none +; +;****************************************************************************** +Interrupt proc far + push ax + push bx + push cx + push dx + push si + push di + push ds + push es + cld ;All strings forward + lds bx,CS:[ReqPtr] ;DS:BX pts to Request Header + mov al,[bx.COMMAND_CODE] ;Get the command code + cmp al,TBL_LENGTH ;Check for validity + jae Invalid ;Jump if command invalid + cbw ;Command to a full word + shl ax,1 ;Compute dispatch index + mov si,OFFSET Cmd_Table ;Point to dispatch table + add si,ax ;Index based on command + call CS:[si] ;Call correct routine + +; +; ENTRY: AX = Status field for Request Header +; +Finish: + lds bx,CS:[ReqPtr] ;Get request header ptr. + or ah,DON ;Set done bit in status + mov DS:[bx.STATUS_WORD],ax ;Save status in header + pop es ;Restore the ES register + pop ds + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret +Invalid: + mov al,UNK_COMMAND ; unknown command + mov ah,ERR ; error + stc + jmp SHORT Finish ;Go return to caller +Interrupt endp + +;****************************************************************************** +; Null_Exit: do nothing +; +; ENTRY: DS:BX pts to request header +; +; EXIT: No error returned. +; CLC +; +;****************************************************************************** +Null_Exit proc near +; + xor ax,ax + clc + ret +; +Null_Exit endp + +;****************************************************************************** +; Init_Call - call initialization routine +; +; ENTRY: DS:BX pts to request header +; +; EXIT: AX = status field for request header +; +;****************************************************************************** +Init_Call proc near +; + call Init_MEMM386 + ret +; +Init_Call endp + +;****************************************************************************** + db 'SBP' + db 'BMT' +;****************************************************************************** +; + +R_CODE ends + + page +;****************************************************************************** +; +; _TEXT Code Segment +; +;****************************************************************************** +_TEXT segment + assume cs:_TEXT, ds:_TEXT, es:_TEXT, ss:_TEXT + +FarLink dd 0 ; far pointer to installed memm386 entry point + ; OK as writeable because it is only used + ; during .EXE execution. + +; +rh db 23,0,0,0,0,8 dup (0) + db 10 dup (0) +; +MEMM: +;****************************************************************************** +; +; ELIM_EXE - .EXE entry point - when MEMM.EXE is invoked as a DOS +; utility. +; +;****************************************************************************** + +;------------------------------------------------------------------------------ +; NOTE** SUNILP .. Paulch changed this to load it as an terminate and stay +; resident. This entry should only be to turn an existing MEMM ON +; OFF or AUTO. Once the driver is debugged change this back to the +; original code given here in comments. Also remove the above rh +; storage block. WISH002 +;ELIM_EXE proc near +;; +; push cs +; pop ds ; ds = cs +; mov ah,GET_PSP ; get segment of PSP +; int MS_DOS +; mov es,bx ; DOS call returned seg in bx +; mov di,offset cmd_line ; es:di = command line +; call onf_func ; look for on, off, or auto +; mov ax,4c00h ; exit to DOS +; int MS_DOS +;; +;ELIM_EXE endp +;; +;------------------------------------------------------------------------------ + +ELIM_EXE proc near +; + extrn exe_stack:byte + + push seg STACK + pop ss + mov sp, offset STACK:exe_stack + push cs + pop ds + mov ah,GET_PSP + int MS_DOS + mov es,bx + mov di,offset cmd_line + + mov bx,seg rh + mov ds,bx + mov bx,offset rh + mov [bx+20],es + mov [bx+18],di + + push ds + pop es + call Strategy + call Interrupt + + mov bx,seg rh + mov es,bx + mov bx,offset rh + mov dx,es:[bx+16] + sub dx,es:[bx+20] + mov ah,31h + int 21h +; + +; push cs +; pop ds ; ds = cs +; mov ah,GET_PSP ; get segment of PSP +; int MS_DOS +; mov es,bx ; DOS call returned seg in bx +; mov di,offset cmd_line ; es:di = command line +; call onf_func ; look for on, off, or auto + mov ax,4c00h ; exit to DOS + int MS_DOS +; +ELIM_EXE endp +; +;****************************************************************************** +; Inst_chk_f - call Inst_chk +; +; ENTRY: see Inst_chk +; +; EXIT: see Inst_chk +; +; USED: none +; +;****************************************************************************** +Inst_chk_f proc far + call Inst_chk + ret +Inst_chk_f endp + +;****************************************************************************** +; Inst_chk - Check to see if MEMM is already installed +; +; ENTRY: int 67 vector +; +; EXIT: ax = 0 if not already installed +; ax = 1 if MEMM is already installed +; _TEXT:[FarLink] = far address for installed MEMM entry point +; +; USED: none +; +;****************************************************************************** +Inst_chk proc near + push di ; save di + push si ; and si + push ds ; and ds + push es ; and es + push cx ; and cx +; + xor ax,ax ; put segment 0000h in ds + mov ds,ax + ASSUME DS:abs0 ; assume ds is abs0 + mov ax,[int67+2] ; get segment pointed to by int 67 + mov es,ax + ASSUME ES:R_CODE + + push seg R_CODE + pop ds ; set DS = R_CODE + assume DS:R_CODE ; update assume + + mov di,offset memmsig ; memm386 signature + mov si,di ; save for source string + xor ax,ax ; initialize to not found + mov cx,SIG_LENGTH ; length to compare + cld ; strings foward + repe cmpsb ; q: is the memm386 signature out there? + jne not_inst ; n: return zero + inc ax ; y: return one + mov word ptr CS:[FarLink+2],es ; set segment of far call + mov cx,ES:[MEMM_Entry] ; get offset for far call + mov word ptr CS:[FarLink],cx ; set offset of far call +not_inst: + + ASSUME DS:_TEXT, ES:_TEXT + + pop cx + pop es + pop ds + pop si + pop di + ret +Inst_chk endp + +;****************************************************************************** +; ELIM_link - Link to Installed MEMM's ELIM_Entry +; +; ENTRY: see ELIM_Entry +; and +; _TEXT:[FarLink] = far address of installed MEMM ELIM_Entry +; +; EXIT: see ELIM_Entry +; +; USED: none +; +;****************************************************************************** +ELIM_link proc near + call CS:[FarLink] + ret +ELIM_link endp + + +_TEXT ends + + end MEMM + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/MEMMCOM.ASM b/v4.0/src/MEMM/MEMM/MEMMCOM.ASM new file mode 100644 index 0000000..b92cfdb --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MEMMCOM.ASM @@ -0,0 +1,243 @@ + + + page 58,132 +;****************************************************************************** + title MEMMCOM - main module for MEMM.COM +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.COM - MICROSOFT Expanded Memory Manager 386 Utility +; +; Module: MEMMCOM - main module for MEMM.COM +; +; Version: 0.02 +; +; Date: June 4, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/04/86 Original +; 06/21/86 0.02 Added CLD to Inst_Chk +; 06/28/86 0.02 Name change from MEMM386.COM to MEMM.COM +; +;****************************************************************************** +; +; Functional Description: +; MEMM.COM which allows the user to poll or set the operating mode +; of the MEMM device driver. +; Syntax: +; MEMM [ ON | OFF | AUTO ] +; +; If the user specifies no arguments, MEMM.COM will return the +; current mode of the MEMM device driver. +; +; ON +; If the user specifies ON, MEMM.COM enables the MEMM driver; +; expanded memory is available and the processor is in virtual mode. +; +; OFF +; If the user specifies OFF, MEMM.COM disables the MEMM driver; +; expanded memory is not available and the processor is in real mode. +; +; AUTO +; If the user specifies AUTO, MEMM.COM enables the MEMM driver's auto +; mode. In auto mode, the driver will enable and disable itself +; "automatically" (depending on accesses to the EMM functions). +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public EMM386 + public Inst_chk + public ELIM_link +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +_TEXT segment byte use16 public 'CODE' + extrn onf_func:near +_TEXT ends +abs0 segment use16 at 0000h + + org 67h*4 ; EMM function interrupt +int67 dw ? ; offset of vector + dw ? ; segment of vector +abs0 ends + + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + +MSDOS equ 21h ; MS-DOS function call + +; +; Device driver header for MEMM +; +emm_hdr STRUC +; + DW ? ;Null segment address + DW ? ;Null offset address + DW ? ;Attribute - Char + DW ? ;Strategy routine entry + DW ? ;Interrupt routine entry + DB 'EMMXXXX0' ;Character device name +; +; GENERAL FUNCTIONS ENTRY POINT +; ELIM_Entry is a entry point for executing general MEMM +; functions. (e.g. ON, OFF function). +; +ELIM_Entry_off dw ? ; general entry point + +; +; MEMM signature +; +memmsig db ? ; MEMM signature + +emm_hdr ends + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +_TEXT segment byte use16 public 'CODE' + assume cs:_TEXT, ds:_TEXT, es:_TEXT, ss:_TEXT + org 81h +cmd_line dw ? ; pointer to command line +; +;****************************************************************************** +; M O D U L E E N T R Y P O I N T +;****************************************************************************** +; +; Standard .COM entry conditions are assumed +; + org 100h +EMM386 proc near + jmp start +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** +; + +oursig db 'MICROSOFT EXPANDED MEMORY MANAGER 386' +SIG_LENGTH equ (this byte - oursig) +; +; define double word to store segment/offset of status routine for far call +; +status_loc label dword +entry_off dw 0 ; store offset for far call +entry_seg dw 0 ; store segment for far call +; + +start: + push cs + pop ds + push cs + pop es + +; + cli + mov sp,offset Stack_Top + sti +; + cld +; + mov di,offset cmd_line ; es:di = command line pointer + call onf_func ; do the on/off function + + mov ax,4C00h + int MSDOS ; exit to DOS + +EMM386 endp + +page +;****************************************************************************** +; ELIM_link - Call ELIM_Entry status routine via the status_loc +; +; ENTRY: [status_loc] contains the far address +; +; EXIT: ? +; +; USED: none +; +;****************************************************************************** +ELIM_link proc near + call status_loc + ret +ELIM_link endp +page +;****************************************************************************** +; Inst_chk - Check to see if MEMM is already installed +; +; ENTRY: int 67 vector +; +; EXIT: ax = 0 if not already installed +; ax = 1 if MEMM is already installed +; If MEMM is installed, then +; [entry_seg] = segment of driver header +; [entry_off] = offset of status routine in MEMM +; +; USED: none +; +;****************************************************************************** +Inst_chk proc near + push di ; save di + push si ; and si + push ds ; and ds + push es ; and es + push cx ; and cx +; + xor ax,ax ; put segment 0000h in ds + mov ds,ax + assume ds:abs0 ; assume ds is abs0 + mov ax,[int67+2] ; get segment pointed to by int 67 + mov es,ax + + assume ds:_TEXT ; update assume + push cs + pop ds ; set DS = _TEXT + + mov di,offset memmsig ; MEMM signature + mov si,offset oursig ; point to our signature + xor ax,ax ; initialize to not found + mov cx,SIG_LENGTH ; length to compare + cld ; strings foward + repe cmpsb ; q: is the MEMM signature out there? + jne not_inst ; n: return zero + inc ax ; y: return one + mov [entry_seg],es ; save segment for far call + xor di,di + mov cx,es:[ELIM_Entry_off] ; save offset for far call + mov [entry_off],cx +not_inst: + pop cx + pop es + pop ds + pop si + pop di + ret +Inst_chk endp + + + db 100h dup (0) +Stack_Top: + db 0 + +_TEXT ends + + end EMM386 + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/MEMMINC.ASM b/v4.0/src/MEMM/MEMM/MEMMINC.ASM new file mode 100644 index 0000000..1eb897f --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MEMMINC.ASM @@ -0,0 +1,80 @@ + + + page 58,132 +;****************************************************************************** + title MEMMINC.ASM - lists all MEMM include files +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager +; +; Module: MEMMINC.ASM - lists all MEMM include files +; +; Version: 0.02 +; +; Date: June 14, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 06/25/86 original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +; Functional Description: +; This module includes all MEMM include files 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 ASCII_SM.EQU + page + include DRIVER.EQU + page + include PIC_DEF.EQU + page + include ROMSTRUC.EQU + page + include ROMXBIOS.EQU + + page + include DESC.INC + page + include ELIM.INC + page + include EMM386.INC + page + include INSTR386.INC + page + include KBD.INC + page + include LOADALL.INC + page + include OEMDEP.INC + page + include PAGE.INC + page + include VDMSEG.INC + page + include VDMSEL.INC + page + include VM386.INC + + page + include DRIVER.STR + + end diff --git a/v4.0/src/MEMM/MEMM/MEMMONF.ASM b/v4.0/src/MEMM/MEMM/MEMMONF.ASM new file mode 100644 index 0000000..5eee389 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MEMMONF.ASM @@ -0,0 +1,337 @@ + + + page 58,132 +;****************************************************************************** + title MEMMONF - (C) Copyright MICROSOFT Corp. 1986 +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: MEMMONF - parse for on/off/auto and perform the function +; +; Version: 0.02 +; +; Date: June 4, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/04/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +; +; Functional Description: +; MEMMONF is used by MEMM.EXE UTILITY code and MEMM.COM to parse +; the command line for ON, OFF, or AUTO and perform the function +; via a call to ELIM_Entry. It also displays the appropriate message +; depending on the results of the parsing and call to ELIM_Entry. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public onf_func + public get_token +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** + + + +_TEXT segment byte use16 public 'CODE' + extrn Inst_chk:near + extrn ELIM_link:near +_TEXT ends +; + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +MSDOS equ 21h ; MS-DOS function call + + include ascii_sm.equ + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +_TEXT segment byte use16 public 'CODE' + assume cs:_TEXT, ds:_TEXT, es:_TEXT, ss:_TEXT +; +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** +; + include memm_msg.inc +; +msg_tbl label word ; table of final messages to display + dw offset vmode ; on + dw offset rmode ; off + dw offset amode ; auto + dw 0 ; no parameter will use above msgs + dw offset parmerr ; invalid parameter + dw offset verr_msg ; error entering vmode + dw offset rerr ; error entering rmode + dw offset aerr ; error entering amode +; +; the valid arguments +; +on_arg db "on" +on_len equ (this byte - on_arg) + +off_arg db "off" +off_len equ (this byte - off_arg) + +auto_arg db "auto" +auto_len equ (this byte - auto_arg) + +null_arg db " " +null_len equ 1 +max_arg_len equ 11 +arg_str db max_arg_len dup(0) ; storage for get_token +; +arg_tbl label word ; table of valid arguments + dw offset on_arg + dw offset off_arg + dw offset auto_arg +; +no_arg equ (this byte - arg_tbl) + dw offset null_arg ; should be last entry +max_args equ (this byte - arg_tbl) +; +arg_len label word ; table of argument lengths + dw on_len + dw off_len + dw auto_len +; + dw null_len + +page +;****************************************************************************** +; onf_func - Check command line for ON OFF or AUTO and perform function +; +; ENTRY: es:di points to command line terminated by CR or LF +; +; EXIT: The appropriate message is displayed +; +; USED: none +; +;****************************************************************************** +onf_func proc near + + push ax + push dx + push di + + cld +; +; check for driver installed +; + call Inst_chk ; ax = 0/1 => isn't/is installed + or ax,ax ; q: is it installed? + jnz drvr_installed + mov dx,offset not_there ; Not installed message + jmp term ; display message and quit +; +drvr_installed: +; + call parse_onf ; look for ON/OFF + jc msg_disp ; invalid parameter + cmp ax,no_arg/2 ; q: no argument? + je get_status ; y: get status + push ax ; save on/off indicator + mov ah,1 ; ah=1 for set status routine + call ELIM_link ; go turn it on or off + pop ax ; restore on/off indicator + jnc get_status ; no error in status routine + add ax,max_args/2+1 ; indicate error + jmp msg_disp +; +get_status: + xor ah,ah ; get status + call ELIM_link ; status in ah + mov al,ah + xor ah,ah ; status in ax + cmp ax,2 ; q: auto mode? + jb msg_disp ; n: display mode + push ax ; save it + mov dx,offset amode + mov ah,9 + int MSDOS ; print auto mode + pop ax ; restore mode + sub ax,2 ; get on or off indicator +; +msg_disp: + shl ax,1 ; make it a word index + mov di,ax ; offset into message table + mov dx,msg_tbl[di] ; get appropriate message +term: + mov ah,9 + int MSDOS ; display error message +; + pop di + pop dx + pop ax + + ret +onf_func endp + + page +;****************************************************************************** +; get_token - Retrieve a non-white-space string from a source string +; +; ENTRY: es:di points to command line terminated by CR or LF +; ds:si points to storage for token +; cx = maximum length to store +; +; EXIT: cx = length of token (0 => end of source string) +; es:di points to first char after new token in source string +; string of length cx stored in ds:si (and converted to lower case) +; +; USED: see above +; +;****************************************************************************** +get_token proc near + push si ; save storage area + push bx + push ax +; + mov bx,cx ; number to store + xor cx,cx ; no chars found so far +; +; go to first non-blank character +; +gloop1: + mov al,es:[di] ; get a character + inc di ; point to next + cmp al,' ' ; Q: space ? + je gloop1 ; y: skip it + cmp al,TAB ; Q: TAB ? + je gloop1 ; y: skip it + dec di ; N: start parsing and reset di +gloop2: + mov al,es:[di] ; get next char + cmp al,CR ; q: carriage return? + je token_xit ; y: quit + cmp al,LF ; q: line feed? + je token_xit ; y: quit + cmp al,' ' ; Q: space ? + je token_xit ; y: quit + cmp al,TAB ; Q: TAB ? + je token_xit ; y: quit + inc di ; n: point to next + inc cx ; increment number of chars found + cmp cx,bx ; q: have we stored our limit yet? + ja gloop2 ; y: don't store any more + or al,20h ; make it lower case + mov ds:[si],al ; store it + inc si ; and point to next + jmp short gloop2 ; continue +token_xit: +; + pop ax + pop bx + pop si + ret +get_token endp + + page +;****************************************************************************** +; parse_onf - Parse command line for ON or OFF +; +; ENTRY: es:di points to command line terminated by CR or LF +; +; EXIT: ax = 0 => ON +; ax = 1 => OFF +; ax = 2 => AUTO +; ax = 3 => no argument encountered +; ax = 4 => Error in command line +; CARRY = cleared if no errors +; set if error (ax will also = 4) +; es:di points to end of parsed string +; +; USED: see above +; +;****************************************************************************** +parse_onf proc near +; + push si + push ds + push bx + push es +; + mov bx,no_arg ; initialize to no parameters encountered + cld ; go foward +; +; es:di = 1st char +; + mov si,offset arg_str ; ds:si = storage for argument + push cs + pop ds ; arg storage in _CODE + mov cx,max_arg_len ; maximum argument length + call get_token ; get an argument + or cx,cx ; q: any parms? + jz parse_xit ; n: quit + push di ; y: save di for later + push ds ; es:di = parameter table + pop es + + xor bx,bx ; index into parameter table +ploop2: + cmp cx,arg_len[bx] ; q: lengths equal? + jne not_found ; n: keep looking + mov di,arg_tbl[bx] ; get destination address + push si ; save source string addr + repe cmpsb ; q: is this a valid argument? + pop si ; restore source string address (command line) + je found ; y: matched one +not_found: + inc bx + inc bx ; update table pointer + cmp bx,max_args ; q: have we done them all yet? + jne ploop2 ; n: keep looking +parse_inv: + mov bx,max_args ; y: invalid + pop di ; restore di + jmp short parse_xit ; leave +found: + pop di ; restore original string addr + pop es + mov cx,1 ; just need to check for one non blank + call get_token ; get another token + or cx,cx ; q: was there another one? + jz parse_xit2 ; n: good + mov bx,max_args ; y: invalid + jmp short parse_xit2 +parse_xit: + pop es +parse_xit2: + shr bx,1 ; get result of parse + mov ax,bx ; put in ax + mov bx,max_args/2-1 + cmp bx,ax ; set/clear carry on invalid/valid return +; + pop bx + pop ds + pop si +; + ret +parse_onf endp + +_TEXT ends + + end diff --git a/v4.0/src/MEMM/MEMM/MEMM_MSG.INC b/v4.0/src/MEMM/MEMM/MEMM_MSG.INC new file mode 100644 index 0000000..da17c94 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MEMM_MSG.INC @@ -0,0 +1,43 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - 386 EMM device driver +; +; Module: CEM_MSG.INC - messages for ON/OFF/AUTO utility +; +; Version: 0.02 +; +; Date: June 7,1986 +; +; Author: +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 06/07/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +; +not_there db "EMM386 driver not installed.",CR,LF,BEL,"$" + +vmode db "EMM386 Active.",CR,LF,"$" + +rmode db "EMM386 Inactive.",CR,LF,"$" + +amode db "EMM386 in Auto mode.",CR,LF,"$" + +verr_msg db "Unable to activate EMM386.",CR,LF,BEL,"$" + +rerr db "Unable to inactivate EMM386.",CR,LF,BEL,"$" + +aerr db "Unable to place EMM386 in Auto mode.",CR,LF,BEL,"$" + +parmerr db "Usage: EMM386 [ ON | OFF | AUTO]" + db CR,LF,BEL,"$" diff --git a/v4.0/src/MEMM/MEMM/MOVEB.ASM b/v4.0/src/MEMM/MEMM/MOVEB.ASM new file mode 100644 index 0000000..00b9a07 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/MOVEB.ASM @@ -0,0 +1,533 @@ + + +page 58,132 +;****************************************************************************** + title MOVEB - move block emulator +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: MOVEB - move block code for MEMM +; +; Version: 0.05 +; +; Date: 05/22/86 +; +; Author: +; +;************************************************************************* +; CHANGE LOG: +; DATE VERSION Description +;--------- -------- -------------------------------------------------- +; 05/15/86 Check source/target selector using verr,verw +; and add parity handler +; 06/09/86 Added MapLinear call +; 06/17/86 Added code to detect and "handle" writes to +; diag byte location. +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/06/86 0.04 DiagByte moved to _DATA +; 07/06/86 0.04 changed assume to DGROUP +; 07/10/86 0.05 Added Real Mode patch code +;************************************************************************* +.386p + + +;**************************************** +; P U B L I C S +;**************************************** + public Move_Block + public MB_Exit + public MB_Stat + public i15_Entry + public MB_Flag + public i15_Old + + page +;**************************************** +; D E F I N E S +;**************************************** + include vdmseg.inc + include vdmsel.inc + include desc.inc + include instr386.inc + include oemdep.inc + include vm386.inc + +TRUE equ 0FFh +FALSE equ 00h + +D_G_BIT equ 80h ; granularity bit in high status bits + +FLAGS_CY equ 0001h +FLAGS_ZF equ 0040h +FLAGS_IF equ 0200h + + ; 386 data descriptor format +DATA_DESC_386 struc +DD386_Limit_lo dw ? ; low word of seg limit +DD386_Base_lo dw ? ; low 24 bits of seg base addr + db ? ; +DD386_Access db ? ; access byte +DD386_L_Stat db ? ; high 4 bits of seg limit + ; and futher status +DD386_Base_hi db ? ; high 8 bits of seg base addr +DATA_DESC_386 ends + + ; format of move block descriptor table passed on entry +MB_GDT struc +MG_dummy dd 2 dup (?) ; dummy descriptor entry +MG_GDT dd 2 dup (?) ; GDT entry +MG_Source dd 2 dup (?) ; source segment entry +MG_Target dd 2 dup (?) ; target segment entry +MB_GDT ends + +;************************************************************ +; DescrMap - map address in descriptor +; ENTRY: ES:DI = descriptor +; EXIT: descriptor's address is mapped by MapLinear +; USED: EAX +;************************************************************ +DescrMap MACRO + mov ah,ES:[di.DD386_Base_hi] ; ah = high 8 bits of address + mov al,byte ptr ES:[di.DD386_Base_lo+2] ; al = bits 16-23 of addr + OP32 + shl ax,16 ; high addr word into high EAX + mov ax,ES:[di.DD386_Base_lo] ; EAX = 32 bit address + call MapLinear ; map linear address + mov ES:[di.DD386_Base_lo],ax ; store low word of address + OP32 + shr ax,16 ; ax = high word of address + mov byte ptr ES:[di.DD386_Base_lo+2],al ; store + mov ES:[di.DD386_Base_hi],ah ; high word of address + ENDM + +;******************************************************************************* +; E X T E R N A L R E F E R E N C E S +;******************************************************************************* +_TEXT segment + + extrn MapLinear:near + extrn Set_Par_Vect:near + extrn Rest_Par_Vect:near + extrn togl_A20:near + extrn get_a20_state:near + +_TEXT ends + +_DATA segment + + extrn Active_Status:byte ; non-zero if in VM + +_DATA ends + + + page +;******************************************************************************* +; D A T A S E G M E N T +;******************************************************************************* +_DATA segment + +MB_Stat db 0 ; move block status +Toggle_st db 0 + +_DATA ends + + page +;**************************************** +; C O D E S E G M E N T _TEXT +;**************************************** +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP + + page +;************************************************************************* +;*** Move_Block - Mimics the 286 ROM function Move Block ( int15h AH=87h ). +; Move a block of data (copy it) to/from anywhere in +; 24bits of linear address space. Normally used to move +; data to/from extended memory (past 1M) since real mode +; can only address the first meg of memory. +; +; +; ENTRY PROTECTED MODE +; AH = 87h +; CX = # of words to move ( max 8000h ). +; ES:SI = ptr to a descriptor table containing segment descriptors +; for the source and target memory of the transfer. +; +; EXIT PROTECTED MODE +; AH = 00 if OK +; 01 if parity error *** currently not checked *** +; 02 if exception error +; 03 if gate address bit A20 fails. +; if no error: +; ZF and NC in client's flags +; if error: +; NZ and CY in client's flags +; +; +; USES AX, FLAGS -> CLD. +; +; Descriptor Table Format +; ES:SI ---> +-------------------------------+ +; | Dummy descriptor | +; +-------------------------------+ +; | GDT descriptor | +; +-------------------------------+ +; | Source segment descriptor | +; +-------------------------------+ +; | Target segment descriptor | +; +-------------------------------+ +; +;************************************************************************* +Move_Block proc near +; + push ds + push es + PUSH_EAX + push cx + push si + push di +; + cld +; + mov ax,VDMD_GSEL ; get data selector + mov ds,ax ; DS = DGROUP + mov [MB_Stat],0 ; init status of move block to OK. +; +; check word count field +; + cmp cx,8000h ;Q: word count too high + jbe MB_chk_length ; N: check length of segments + jmp MB_Excp_Error ; Y: report exception error + +; +; check source and target descriptor's lengths against transfer count +; only need check low word since caller set up a 286 descriptor +; +MB_chk_length: + mov ax,cx + shl ax,1 ; AX = # of bytes to transfer(0=>8000h) + dec ax ; convert to seg limit type value + ; ( 0FFFFh => 64K ) + cmp ax,ES:[si.MG_Source.DD386_Limit_lo] ;Q: source seg limit low ? + jbe MB_chk_tarl ; N: chk target length + jmp MB_Excp_Error ; Y: return excp error. + +MB_chk_tarl: + cmp ax,ES:[si.MG_Target.DD386_Limit_lo] ;Q: tar seg too small ? + jbe MB_setup ; N: seg limits OK. + jmp MB_Excp_Error ; Y: return excp error +; +; source and target descriptors OK, set up scratch selector descriptors +; + +MB_setup: + push cx ; save copy count + + push es + pop ds ; set DS:SI to input descriptor table + mov ax,GDTD_GSEL + mov es,ax ; ES:0 pts to GDT + mov di,MBSRC_GSEL ; ES:DI pts to source work descriptor in GDT + push si ; save input descr table ptr + lea si,[si.MG_Source]; DS:SI pts to input source descr + mov cx,4 + rep movsw ; set move block source work descr + pop si ; restore input descr table ptr + mov di,MBSRC_GSEL ; ES:DI pts to source work descriptor in GDT + call MB_Map_Src + DescrMap ; fixup this descriptor's linear address + + mov di,MBTAR_GSEL ; ES:DI pts to target work descr in GDT + push si ; save input descr table ptr + lea si,[si.MG_Target] ; DS:SI pts to input target descr + mov cx,4 + rep movsw ; set move blk target work descr + pop si ; restore input descr table ptr + mov di,MBTAR_GSEL ; ES:DI pts to target work descr in GDT + call MB_Map_Dest + DescrMap ; fixup this descriptor's linear address + +; +; install NMI/parity exception handler +; + call Set_Par_Vect ; restore the parity interrupt handler + +; +; copy the data +; + +; +; check if a20 line is to be enabled or not +; + call get_a20_state + jnz a20_is_enb +; +; a20 line is currently disabled. we need to enable the a20 +; + call togl_a20 + mov [toggle_st],0ffh +a20_is_enb: +; + pop cx ; restore copy count + + xor di,di + xor si,si + mov ax,MBSRC_GSEL + verr ax ;Q: source selector valid ? + jnz MB_Excp_Error ; N: return exception error + mov ds,ax ; Y: DS:SI pts to source segment + mov ax,MBTAR_GSEL + verw ax ;Q: target selector valid ? + jnz MB_Excp_Error ; N: return exception error + mov es,ax ; Y: ES:DI pts to target segment + jmp MB_move_block ; and go ahead +; +; Error reporting +; +MB_Excp_Error: + mov ax,VDMD_GSEL ; get data selector + mov ds,ax ; DS = DGROUP + mov [MB_Stat],2 + jmp MB_Exit +; +; move the block +; +MB_move_block: + + call MB_Start + +; +; MOVE the BLOCK - dwords +; + test cx,01h ;Q: move an odd # of words? + jz MB_moved ; N: move dwords + movsw ; Y: move the first one => dwords now +MB_moved: + shr cx,1 ; move CX dwords... + OP32 + rep movsw ; REP MOVSD + + mov ax,VDMD_GSEL ; get data selector + mov ds,ax ; DS = DGROUP + +; restore a20 state to what it was before this routine +; + test [toggle_st],0ffh ; do we need to toggle the a20 back? + jz a20_restored ; N: skip toggling + call togl_a20 ; Y: else toggle the A20 line +a20_restored: + mov [toggle_st],0 ; clear this flag + + jmp MB_Exit +Move_Block endp + +;************************************************************************* +; This is special JUMP entry point for parity handler +; +MB_Exit proc near +; +; reset NMI handler +; + + call Rest_Par_Vect ; restore the parity interrupt handler + +; +; +MB_leave: + pop di + pop si + pop cx + POP_EAX + mov ah,[MB_Stat] +; +; set client's flags to no error +; + or [bp.VTFOE+VMTF_EFLAGS],FLAGS_ZF ; ZF + and [bp.VTFOE+VMTF_EFLAGS],NOT FLAGS_CY ; NC + + or ah,ah ;Q: error occured ? + jz MB_ret ; N: continue + ; Y: set error in client's flags + and [bp.VTFOE+VMTF_EFLAGS],NOT FLAGS_ZF ; NZ + or [bp.VTFOE+VMTF_EFLAGS],FLAGS_CY ; CY +; +MB_ret: + pop es + pop ds + ret +; +MB_Exit endp + +_TEXT ends + + page +;**************************************** +; C O D E S E G M E N T R_CODE +;**************************************** +R_CODE segment + assume cs:R_CODE, ds:DGROUP, es:DGROUP + +;************************************************************************* +; local data +;************************************************************************* +I15_Old dd 0 ; old Int 15h handler +MB_Flag db 0 ; non-zero => do move block in ring 0 +Exit_Flags dw 0 ; flags for int15 exit +; +ext_mem_size dw 0 ; we are using new int 15 allocation + ; scheme now whereby we have to lower + ; the size reported by int 15 function + ; 88h to grab some memory for ourself + ; The extended memory allocate routine + ; in allocmem.asm fills in the approp. + ; size here. + + page +;************************************************************************* +; i15_Entry - real/virtual mode patch code for int 15h +; +; This function patches the real mode IDT for MEMM. If it is +; entered for a move block, this code sets a flag to tell MEMM to +; pick up the move block, then i15_Entry lets MEMM do it. Otherwise +; MEMM jumps to the previous code. For function 88h it reports the +; the new size of extended memory. +; +; ENTRY Real/Virtual mode +; see int15h entry parameters in ROM spec +; +; EXIT +; +; 87h: Real/Virtual mode +; AH = 00 if OK +; 01 if parity error *** currently not checked *** +; 02 if exception error +; 03 if gate address bit A20 fails. +; if no error: +; ZF and NC in client's flags +; if error: +; NZ and CY in client's flags +; +; 88h: Real/Virtual mode +; AX = Size of extended memory in KB +; +; +; USES AX, FLAGS -> CLD. +; +; NOTE:**ISP This routine was modified to implement the new INT15 allocation +; scheme whereby MEMM by lowering the size of extended memory could +; grab the difference between the old size and the new size reported +; for itself. +;************************************************************************* +i15_flags equ 6 +i15_cs equ 4 +i15_ip equ 2 +i15_bp equ 0 + +i15_Entry proc near +; + cli ; in case of pushf/call far + pushf ; save entry flags +; +; Check to see if it is the extended memory size request +; + cmp ah,88h ;Q: extended memory size request? + jne chk_blk_move ; N: go to check for move block call +; +; Implement int15 allocation scheme by reporting a lowered value of extended +; memory. + popf + mov ax,cs:[ext_mem_size] ; report new extended memory size + iret ; +; +; Checking for move block call +; +chk_blk_move: + cmp ah,87h ;Q: move block call ? + jne i15_jmpf ; N: jmp to old code + push ds + push seg DGROUP ; + pop ds ; DS -> DOSGROUP + cmp [Active_Status],0 ; Y: Q: in Virtual mode ? + pop ds ; reset DS + je i15_jmpf ; N: jmp to old code + ; Y: VM move block + mov CS:[MB_Flag],TRUE ; let MEMM have it ... + popf ; retrieve entry flags (IF cleared!!!) + int 15h ; give it to MEMM + ; MEMM will reset MB_Flag + cli ; just in case + push bp ; save bp + mov bp,sp + push ax ; save ax + pushf + pop ax ; AX = exit flags + xchg ax,[bp+i15_Flags] ; AX = entry flag, exit flags on stack + and ax,FLAGS_IF ; save only IF bit of entry + or [bp+i15_Flags],ax ; set IF state in flags on stack + pop ax + pop bp + iret ; and leave +; +; far jump to old code +; +i15_jmpf: + popf ; retrieve entry flags + jmp CS:[i15_Old] +; +i15_Entry endp + +R_CODE ends + + +LAST SEGMENT +; + ASSUME CS:LAST +; +public set_ext +; +;************************************************************************* +; set_ext - to fill up size of extended memory reported by int 15 +; +; This function fills up the size of extended memory reported by the +; int 15 real/virtual mode patch. +; +; ENTRY Real Mode +; bx=size of extended memory in Kb +; +; EXIT None. R_CODE:ext_mem_size filled. +; +; USES None. +; +; WRITTEN 7/25/88 ISP +; +;************************************************************************* + +set_ext proc near +; + ASSUME DS:NOTHING,ES:NOTHING + + push ax + push ds +; + mov ax,seg R_CODE + mov ds,ax +; + ASSUME DS:R_CODE +; + mov [ext_mem_size],bx +; + pop ds + pop ax +; + ASSUME DS:NOTHING +; + ret +; +set_ext endp +; + +LAST ENDS + end diff --git a/v4.0/src/MEMM/MEMM/M_STATE.ASM b/v4.0/src/MEMM/MEMM/M_STATE.ASM new file mode 100644 index 0000000..9961558 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/M_STATE.ASM @@ -0,0 +1,114 @@ + + + page 58,132 +;****************************************************************************** + TITLE M_STATE:MODULE to establish machine state at emm boot time +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: M_STATE +; +; Version: 0.01 +; +; Date: Aug 29,1988 +; +; Author: ISP (ISP) +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +;****************************************************************************** +; Functional Description: +; +;****************************************************************************** +.lfcond +.386p + + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** + + public estb_mach_state + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + +;****************************************************************************** +; INCLUDE FILES +;****************************************************************************** + include vdmseg.inc ; segment definitions + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +; +_DATA segment +_DATA ends + +; +LAST segment +; + extrn estb_a20_state:near +; +LAST ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + + +;****************************************************************************** +; +; Code Segments +; +;****************************************************************************** +; +_TEXT segment +_TEXT ends + +LAST segment + assume cs:LAST, ds:DGROUP, es:DGROUP + + page +;-----------------------------------------------------------------------; +; estb_mach_state ; +; ; +; establishes the state of the machine at memm boot. the only thing we ; +; are concerned about right now is the a20 state which needs to be ; +; preserved via emulation ; +; ; +; Arguments: ; +; nothing ; +; Returns: ; +; nothing ; +; Alters: ; +; flags ; +; Calls: ; +; estb_a20_state ; +; History: ; +; ISP (isp). ; +;-----------------------------------------------------------------------; +estb_mach_state proc near +; + call estb_a20_state + ret +; +estb_mach_state endp + +LAST ends ; End of segment +; + + end ; End of module + diff --git a/v4.0/src/MEMM/MEMM/OEMDEP.INC b/v4.0/src/MEMM/MEMM/OEMDEP.INC new file mode 100644 index 0000000..0a2607d --- /dev/null +++ b/v4.0/src/MEMM/MEMM/OEMDEP.INC @@ -0,0 +1,111 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: OEMDEP.INC +; +; Version: 0.04 +; +; Date: June 13, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/13/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/05/86 0.04 Moved Diagbyte to _DATA +; 07/06/86 0.04 Change from _DATA assume to DGROUP +; 08/06/86 0.05 Broke out OEMPROC.ASM from OEMDEP.INC +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + + +_TEXT segment + +extrn MaskIntAll:near ; Mask interrupts routine +extrn RestIntMask:near ; restore interrupt mask routine + +extrn Map_Lin_OEM:near ; MapLinear hook +extrn UMap_Lin_OEM:near ; UnMapLinear hook +extrn MB_Map_Src:near ; Move block map source hook +extrn MB_Map_Dest:near ; Move block map destination hook +extrn MB_Start:near ; Move block start move hook + +_TEXT ends + + +LAST segment + +extrn VerifyMachine:near ; Verify machine valid for software + +LAST ends + +ifndef NOHIMEM ; only for high memory + +;Define routines in OEMPROC module + +_TEXT segment + +extrn HwMemLock:near +extrn HwMemUnlock:near + +_TEXT ends + +LAST segment + +extrn hbuf_chk:near +extrn HiAlloc:near +extrn HiSysAlloc:near +extrn HImod:near +extrn LockROM:near +extrn UnLockROM:near + +LAST ends + +endif + +;****************************************************************************** +; +; HwTabUnlock - unlocks high system RAM - makes tables writeable +; +; EXIT: FS points to DIAG segment +; high system RAM writeable +; +HwTabUnlock MACRO +ifndef NOHIMEM ; only for high memory + call HwMemUnlock +endif + ENDM + +;****************************************************************************** +; +; HwTabLock - update client's hi system RAM write locks state +; +; ENTRY: CS = _TEXT +; CS:[DiagByte] = last byte written to diag byte by user. +; +; EXIT: high system RAM write protect ON or OFF depenending on +; write protect bit in CS:[DiagByte]. +; Bit 1 = 0 => write protect ON +; Bit 1 = 1 => write protect OFF +; +HwTabLock MACRO +ifndef NOHIMEM ; only for high memory + call HwMemLock +endif + + ENDM + +.list ; end of OEMDEP.INC diff --git a/v4.0/src/MEMM/MEMM/OEMPROC.ASM b/v4.0/src/MEMM/MEMM/OEMPROC.ASM new file mode 100644 index 0000000..b5e4931 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/OEMPROC.ASM @@ -0,0 +1,1120 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: OEMPROC.ASM +; +; Version: 0.05 +; +; Date: June 13, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/13/86 Original Separated out OEMPROC from OEMDEP.INC +; +;****************************************************************************** +; +.386p +.lfcond ; list false conditionals + +public VerifyMachine +public MaskIntAll +public RestIntMask +public OEM_Trap_Init +public Map_Lin_OEM +public UMap_Lin_OEM +public MB_Map_Src +public MB_Map_Dest +public MB_Start +public Rest_Par_Vect +public Set_Par_Vect + +public DisableNMI +public ROM_BIOS_Machine_ID +public OEM_Init_Diag_Page + + +ifndef NOHIMEM + +public hi_size +public hi_alloc +public hisys_alloc + +public HwMemLock +public HwMemUnlock + +public Hi_Mem_Size +public hbuf_chk +public HiAlloc +public HiSysAlloc +public HImod + +public InitLock +public LockROM +public UnLockROM + + +endif + + include page.inc + include vdmseg.inc + include VDMsel.inc + include desc.inc + include Instr386.inc + include romxbios.equ + + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +_DATA segment + extrn gdt_mb:word + extrn MB_Stat:word +_DATA ends + + +LAST segment + extrn set_src_selector:near + extrn set_dest_selector:near + extrn SetPageEntry:near +LAST ends + +_TEXT segment + extrn MB_Exit:near +_TEXT ends + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + +MASTER_IMR equ 21h ; mask port for master 8259 + +; +; PPI port bit definitions +; +PPI equ 61h +PPO equ 61h +PPO_MASK_IOCHECK equ 04h ; disable system board parity check +PPO_MASK_PCHECK equ 08h ; disable IO parity check + +RTC_CMD equ 70h ; Real Time Clock cmd port +DISABLE_NMI equ 80h ; mask bit for NMI +ENABLE_NMI equ 00h ; this command to RTC_CMD enables NMI + +;****** REMOVE BEFORE DISTRIBUTION begin +; Compaq specific 386 related addresses +; +X_HI_MEM_SEG equ 0f000h ;segment for the following words +X_MT_386 equ 0fffeh ; Machine type +X_RT_386 equ 0ffe8h ; Rom type +X_HI_PTR equ 0ffe0h ; pointer to four words (offsets below) +X_MEM_BOARD equ 0 ; 32-bit memory board status word +X_HISYS equ 0 ; low byte = # of free 4k system pages +X_AVAIL_MEM equ 4 ; available hi memory in 16 byte chunks +X_LAST_HI equ 6 ; last used byte in hi memory (grows down) +; +; Addresses and values used to write the "ROM" +; +OEM_MEM_HI equ 80c0h ; Upper 16 bits of high mem physical adr +LOCK_ADR_LO equ 0000h ; 0:15 of 32-bit location +LOCK_ADR_HI equ OEM_MEM_HI ; 16-31 of 32-bit location +LOCK_ROM equ 0fcfch ; value to write to lock rom +UNLOCK_ROM equ 0fefeh ; value to write to unlock rom + + + +DIAGSEG segment use16 at 0 +DiagLoc dw ? ; 32 bit memory board diagnostic byte +DIAGSEG ends + + +; +; data definitions +; +_DATA segment + +NMI_Old db 8 dup (0) ; save area for old NMI handler + +NMI_New label byte ; descriptor for new NMI handler +IDT_ENTRY VDMC_GSEL,,D_386INT0 + +; +ifndef NOHIMEM ; if high memory in this model +;Next two entries MUST stay together! +hbase_addr_l dw 0000h ; 24 bit address of beginning of hi memory +hbase_addr_h db 00h ; pool of EMM pages. +; +hi_size dw 0 ; size of hi memory in kbytes +hi_alloc dw 0 ; actual hi memory allocated (due to potential waste) +hisys_alloc dw 0 ; amount of hi system memory allocated in 4k bytes +; +DiagAddr db 0 ; set this when writting to diag byte location +DiagByte db LOW LOCK_ROM ; most recent diag byte written by user +buffer dw 0 ; buffer for 1 word move blocks +endif + + +int_mask db ? ; save for restoring masked interrupts + +; +ROM_BIOS_Machine_ID db 0fch ; hard coded right now to AT model byte. + ; should be changed to be initialised at + ; init time ...isp + + +_DATA ends +;****** REMOVE BEFORE DISTRIBUTION end + + +_TEXT segment + ASSUME CS:_TEXT, DS:DGROUP + +;****************************************************************************** +; +; MaskIntAll Save current interrupt mask state and mask all interrupts +; +; entry: DS pts to DGROUP +; +; exit: All interrupts disabled +; +; used: AX +; +; stack: +; +;****************************************************************************** +MaskIntAll proc near + in al,MASTER_IMR + mov [int_mask], al + mov al,0ffh ;;; all OFF + out MASTER_IMR,al + ret +MaskIntAll endp + +;****************************************************************************** +; +; RestIntMask Restore interrupt mask saved in MaskIntAll +; +; entry: DS pts to DGROUP +; +; exit: Interrupts restored to state previous to MaskIntAll +; +; used: AX +; +; stack: +; +;****************************************************************************** +RestIntMask proc near + mov al,[int_mask] ; restore interrupt mask + out MASTER_IMR,al + ret +RestIntMask endp + +;****************************************************************************** +; OEM_Trap_Init - turn on I/O bit map trapping for I/O port watching +; +; ENTRY: DS -> DGROUP - real,virtual, or protected mode +; ES -> TSS segment +; Trap_Tab already has address of OEM_Handler for ??? ports +; +; Description: This routine is used to initialize any data structures, +; including the IOBitMap(via PortTrap call) used for trapping I/O ports +; when going into virtual mode. The routine(s) used to handle the +; trap(s) should already be installed in the IOTrap_tab table. +; See RRTrap.asm for an example. +; +; EXIT: IO_BitMap Updated to trap ports used for ??? +; +; USED: AX,Flags +; STACK: +;------------------------------------------------------------------------------ + assume cs:_TEXT, ds:DGROUP, es:TSS +OEM_Trap_Init proc near +; +; Initialize data structures +; +; +; Set IOBM traps to look for client's disabling of the A20 line +; +; push bx +; mov bh, 80h ; set every 1k +; mov ax, ??? ; AX = port num to trap +; call PortTrap ; set traps on ??? port +; +; mov ax,0FFFFh +; mov [???],ax ; Initialize trap data structure +; pop bx + + ret +; +OEM_Trap_Init endp +; + +ifndef NOHIMEM ; only for high memory + +;****************************************************************************** +; +; HwMemUnlock - unlocks high system RAM - makes tables writeable +; +; ENTRY: None +; +; EXIT: If NOHIMEM, does nothing, else: +; FS points to DIAG segment +; high system RAM writeable +; + assume cs:_TEXT, ds:NOTHING, es:NOTHING +HwMemUnlock proc near + push OEM0_GSEL + POP_FS ; set FS to diag segment + ASSUME DS:DIAGSEG + FSOVER + mov word ptr [DiagLoc],UNLOCK_ROM + ret +HwMemUnlock endp + + + +;****************************************************************************** +; +; HwMemLock - update client's hi system RAM write locks state +; +; ENTRY: CS = _TEXT(Protected mode) +; DGROUP:[DiagByte] = last byte written to diag byte by user. +; +; EXIT: high system RAM write protect ON or OFF depenending on +; write protect bit in CS:[DiagByte]. +; Bit 1 = 0 => write protect ON +; Bit 1 = 1 => write protect OFF +; + assume cs:_TEXT, ds:NOTHING, es:NOTHING +HwMemLock proc near + + push VDMD_GSEL + POP_FS ; FS = DGROUP + assume ds:DGROUP + FSOVER + test [DiagByte],02h ;Q: client's ROM write protected? + + push OEM0_GSEL + POP_FS ; set FS to diag segment + ASSUME DS:DIAGSEG + + jz HTL_wp ; Y: then write protect ON + FSOVER ; N: then write protect OFF + mov word ptr [DiagLoc],UNLOCK_ROM + jmp short HTL_exit +HTL_wp: + FSOVER + mov word ptr [DiagLoc],LOCK_ROM +HTL_exit: + ret +HwMemLock endp + +endif ;end of "high" memory routines(ifndef NOHIMEM) + +;****************************************************************************** +; +; Map_Lin_OEM Map OEM high memory from physical to linear address +; +; description: This maps an attempt to access the "high" memory to the +; area starting at 16Meg, which the page tables map to the +; proper physical address. +; +; entry: EAX = physical address to map to linear address +; +; exit: If address has been mapped in AX, CF = 1, else CF = 0. +; +; used: AX +; +; stack: +; +;****************************************************************************** +; + assume cs:_TEXT, ds:NOTHING, es:NOTHING +Map_Lin_OEM proc near + OP32 + cmp ax,0000h + dw OEM_MEM_HI ;Q: Addr in diags byte region ? + clc + jne Mp_Lin_Exit ; N: return, CF = 0(no mapping done) + OP32 ; Y: set EAX to proper seg address for diags + sub ax,0000h + dw (OEM_MEM_HI - 0100h); move to 0100h segment +ifndef NOHIMEM +; set write to diag byte flag + push ds ; save DS + push VDMD_GSEL + pop ds ; DS = DGROUP + ASSUME DS:DGROUP + mov [DiagAddr],1 ; set flag for diag addr + pop ds ; reset DS +endif + stc +Mp_Lin_Exit: + ret +Map_Lin_OEM endp + + + +;****************************************************************************** +; +; UMap_Lin_OEM Map OEM high memory from linear to physical address +; +; description: This maps an attempt to access the "high" memory in the +; linear address area starting at 16Meg, to the proper physical +; address. +; +; entry: EAX = linear address to map to physical address +; +; exit: EAX = physical address +; +; used: EAX +; +; stack: +; +;****************************************************************************** +; + assume cs:_TEXT, ds:NOTHING, es:NOTHING +UMap_Lin_OEM proc near + OP32 ; Y: set EAX to physical address for diags + add ax,0000h + dw (OEM_MEM_HI - 0100h) ; move to OEM_MEM_HI segment + ret +UMap_Lin_OEM endp + +;****************************************************************************** +; +; MB_Map_Src Do special move block processing before source mapping +; +; description: +; This routine is called just before MoveBlock does mapping of +; the source. In conjunction with the Map_Lin_OEM routine, and +; the MB_Start routine, it can perform special processing on the +; data moved. +; +; entry: ES:DI pts to source work descr in GDT +; +; exit: any flag setting or perturbation of descriptor is done +; +; used: none +; +; stack: +; +;****************************************************************************** + assume cs:_TEXT, ds:NOTHING, es:NOTHING +MB_Map_Src proc near + ret +MB_Map_Src endp + +;****************************************************************************** +; +; MB_Map_Dest Do special move block processing before destination mapping +; +; description: +; This routine is called just before MoveBlock does mapping of +; the destination. In conjunction with the Map_Lin_OEM routine, +; and the MB_Start routine, it can perform special processing on +; the data moved. +; +; entry: ES:DI pts to destination work descr in GDT +; +; exit: any flag setting or perturbation of descriptor is done +; +; used: AX +; +; stack: +; +;****************************************************************************** + assume cs:_TEXT, ds:NOTHING, es:NOTHING +MB_Map_Dest proc near +ifndef NOHIMEM + push ds + push VDMD_GSEL + pop ds ; DS = DGROUP alias selector + ASSUME DS:DGROUP + mov [DiagAddr],0 ; reset diag addr flag before write + pop ds ; reset DS +endif + ret +MB_Map_Dest endp + +;****************************************************************************** +; +; MB_Start Do any special move block processing +; +; description: +; This routine is called just before MoveBlock does the move. +; It allows for any special processing of data moved +; +; entry: DS is source selector +; ES is destination selector +; SI is source offset +; DI is destination offset +; +; exit: nothing +; +; used: AX +; +; stack: +; +;****************************************************************************** + assume cs:_TEXT, ds:NOTHING, es:NOTHING +MB_Start proc near +ifndef NOHIMEM +; +; check for write to diag byte location +; + push es + push VDMD_GSEL + pop es ; ES = DGROUP alias + ASSUME ES:DGROUP + cmp es:[DiagAddr],0 ;Q: does target -> diag byte ? + je MB_nodiag ; N: then don't worry + mov al,[si] ; Y: get current diag byte + mov es:[DiagByte],al ; and save it where we can access it +MB_nodiag: + pop es ; restore es +endif + ret +MB_Start endp + +;************************************************************************* +; Set_Par_Vect - Set parity handling routine to routine below +; +; Description: +; This routine sets up a parity handling routine in case of +; a parity error during a MOVEBLOCK. +; +; ENTRY: protected mode +; +; EXIT: vector restored +; +; USES: AX, CX, ES, DS, DI, SI +; +; note: entry is from protected mode -> DS,ES are same as during +; move block. +;************************************************************************* + assume cs:_TEXT, ds:NOTHING, es:NOTHING +Set_Par_Vect proc near + mov ax,VDMD_GSEL + mov es,ax ; ES pts to DGROUP + mov ax,IDTD_GSEL ; + mov ds,ax ; DS points to IDT + + mov si,0010h ; DS:[SI] points to NMI descr address in IDT + mov di,offset DGROUP:NMI_Old ; ES:[DI] pts to store area + mov cx,2 + db 66h + rep movsw ; store 2 dwords - save current NMI descriptor + push ds + push es + pop ds ; DS = DGROUP + pop es ; ES = IDT + mov di,0010h ; ES:[DI] points to NMI descr address in IDT + mov si,offset DGROUP:NMI_New ; DS:[SI] pts to new NMI descr + mov cx,2 + db 66h + rep movsw ; set up new NMI descriptor in IDT + ret +Set_Par_Vect endp + +;************************************************************************* +; Rest_Par_Vect - restore parity handling routine to original +; +; Description: +; This routine restores the parity handling vector to the +; contents before Set_Par_Vect was called. It is called after +; a MOVEBLOCK has been completed. +; +; ENTRY: DS = DGROUP +; +; EXIT: vector restored +; +; USES: AX, CX, ES, DI, SI +; +; note: entry is from protected mode -> DS,ES are same as during +; move block. +;************************************************************************* + assume cs:_TEXT, ds:DGROUP, es:NOTHING +Rest_Par_Vect proc near +ifndef NOHIMEM + call HwMemUnlock ; in case IDT is in high mem +endif + mov ax,IDTD_GSEL ; selector for IDT + mov es,ax ; ES points to IDT + + mov di,0010h ; ES:[DI] points to NMI descr address in IDT + mov si,offset DGROUP:NMI_Old ; DS:[SI] pts to store area + mov cx,2 + db 66h + rep movsw ; restore previous NMI descriptor +ifndef NOHIMEM + call HwMemLock +endif + ret +Rest_Par_Vect endp + + +;************************************************************************* +; Parity_Handler - routine to handle parity errors which occur during +; move_block. +; Description: +; This routine writes to the parity error location to +; clear the parity error on the memory board, then it clears +; the parity error on the system board. +; +; note: entry is from protected mode -> DS,ES are same as during +; move block. +;************************************************************************* + assume cs:_TEXT, ds:NOTHING, es:NOTHING +Parity_Handler proc far +; + dec si + dec si ;;; DS:SI pts to address causing parity error + mov ax,[si] ;;; retrieve value and write it back + mov [si],ax ;;; to reset parity on memory board. + in al,PPI ;;; Get parity error flags, reset then set + jmp $+2 ;;; parity checking to reset parity on + jmp $+2 ;;; system board + or al,PPO_MASK_IOCHECK ;;; disable IOCHECK + or al,PPO_MASK_PCHECK ;;; disable PCHECK + out PPO,al ;;; disable them + jmp $+2 + jmp $+2 + jmp $+2 + +ifndef NOHIMEM + call HwMemlock ;;; LOCK high sys mem +endif + + and al, NOT PPO_MASK_IOCHECK ;;; enable IOCHECK + and al, NOT PPO_MASK_PCHECK ;;; enable PCHECK + out PPO,al ;;; enable them + ;;; system board parity now reset + +; + mov ax,VDMD_GSEL ;;; + mov ds,ax ;;; set DS to data seg + assume ds:DGROUP + mov [MB_Stat],1 ;;; set parity error + add sp,12 ;;; remove NMI stuff from stack + jmp MB_Exit ;;; and exit move block + +Parity_Handler endp + +;************************************************************************* +; DisableNMI - This is called by the NMI handler to disable the +; NMI interrupt(stop gracefully) as part of the +; graceful handling of the NMI interrupt. +; +; Description: +; +; note: entry is from 386 protected mode +;************************************************************************* + assume cs:_TEXT, ds:NOTHING, es:NOTHING +DisableNMI proc near + push ax + mov al,DISABLE_NMI + out RTC_CMD,al + pop ax + ret +DisableNMI endp + +_TEXT ends + +LAST segment + +;****************************************************************************** +; +; VerifyMachine Check ID, etc. to make sure machine is 386 valid for +; running the LIM/386 product. +; +; description: +; This routine should check ROM signature bytes and any other +; hardware features that guarantee the appropriateness of running this +; software on the machine. +; +; entry: DS pts to DGROUP +; CF = 1 if from INIT procedure, CF = 0 if from AllocMem procedure +; REAL or VIRTUAL MODE +; +; exit: If not correct machine, CF = 1, else CF = 0. +; +; used: AX +; +; stack: +; +;****************************************************************************** +; + assume cs:LAST, ds:NOTHING, es:NOTHING +VerifyMachine proc near + pushf + push es ; save es + push bx ; save bx + mov bx,X_HI_MEM_SEG ; segment of hi memory control words + mov es,bx ; into es + mov ax,es:X_MT_386 ; get machine type + cmp al,0FCh ; q: is this an AT class machine? + mov ax,es:X_RT_386 ; get ROM type + pop bx ; restore bx + pop es ; restore es + jne inc_prcf ; n: invalid + popf + jc Cor_Prc ; that's all the checking for INIT + cmp ax,'30' ; q: is this a 386? (really '03') + jne inc_prc +Cor_Prc: + clc + ret +inc_prcf: + popf +inc_prc: + stc + ret +VerifyMachine endp ; End of procedure + + +ifndef NOHIMEM ; if high memory in this model +;****************************************************************************** +; +; Hi_Mem_Size - returns pointer and size of high mem allocated to EMM +; +; entry: +; +; exit: if ZF = 1, no high memory allocated to EMM, else +; EAX = 24 bit pointer to EMM allocated high memory +; CX = kbytes of high memory allocated +; +; used: EAX, CX(returned values) +; +; stack: +; +;****************************************************************************** +; + assume cs:LAST, ds:DGROUP, es:NOTHING +Hi_Mem_Size proc near + mov cx,[hi_size] ; CX = kbytes of high mem + shr cx,4 ;Q: any hi memory pages ? CX = pg cnt + jz Hi_Mem_SXit ; N: Exit with ZF = 1 + db 66h ; Y: get high memory pointers + mov ax,[hbase_addr_l] ; get pointer to high memory pool + db 66h + and ax,0FFFFh ; AND EAX,00FFFFFFh + dw 00FFh ; clear highest nibble +Hi_Mem_SXit: + ret +Hi_Mem_Size endp + + page +;****************************************************************************** +; +; hbuf_chk Hi memory pool check. +; Check available hi memory pool space +; +; entry: +; +; exit: If hi memory pool space is available then +; AX = size of memory available and CF = 0 +; else AX = 0 and CF = 1 +; +; used: AX(returned value) +; +; stack: +; +;****************************************************************************** +; + assume cs:LAST, ds:DGROUP, es:NOTHING +hbuf_chk proc near + push es ; save es + push bx + mov bx,X_HI_MEM_SEG ; segment of hi memory control words + mov es,bx + mov bx,es:X_HI_PTR ; pointer to hi memory control words + mov ax,es:[bx+X_MEM_BOARD] ; 32-bit memory board status + inc ax ; q: memory board status word == -1? + stc + jz hbuf_xit ; y: not installed + mov ax,es:[bx+X_AVAIL_MEM] ; get available memory in 16 byte pieces + mov bx,es:[bx+X_LAST_HI] ; get last used address + and bx,0ffh ; align to 4k byte boundary (2**8)*16 + sub ax,bx ; ax = available 16 byte pieces + shr ax,10 ; ax = available 16k byte pieces + shl ax,4 ; ax = available 1k byte pieces + clc +hbuf_xit: + pop bx ; ax = availble memory unless CF = 1 + pop es + ret +hbuf_chk endp +; + page +;****************************************************************************** +; +; HiAlloc - allocate hi memory - update hi memory control words +; +; entry: REAL or VIRTUAL MODE +; DS pts to DGROUP +; DGROUP:[hi_size] size in kbytes to allocate +; +; exit: update available hi memory and last used address. +; Set [hbase_addr_l] and [hbase_addr_h] to starting address. +; If error occurs in writing control words, CF = 1, else CF = 0. +; +; used: none +; +; stack: +; +;****************************************************************************** + assume cs:LAST, ds:DGROUP, es:NOTHING +HiAlloc proc near +; + push ax + push bx + push cx + push dx + push si + push es +; + mov ax,[hi_size] ; get amount of hi memory to allocate + or ax,ax ; q: allocate any? + jz Hi_xit ; n: quit(CF = 0) + + mov cl,6 + shl ax,cl ; back to 16 byte pieces +; + mov bx,X_HI_MEM_SEG ; high memory segment + mov es,bx + mov bx,es:X_HI_PTR ; pointer to high memory control words + mov cx,0ffh ; determine waste by aligning to 4k + and cx,es:[bx+X_LAST_HI] ; cx = extra needed to align + add ax,cx ; ax = total to allocate + mov [hi_alloc],ax ; save it in case we need to put it back + xor bx,bx ; bx = no hi system memory to alloc + call HImod ; go allocate it + ; ax = start of this hi memory + jc Hi_xit ; error occurred during move block(CF=1) + mov cx,16 + mul cx ; make it 24 bits + add dl,0f0h ; last 1M segment + mov [hbase_addr_h],dl ; save starting address of hi mem + mov [hbase_addr_l],ax + clc +; +Hi_xit: ; CF = 1 if error, else CF = 0 + pop es + pop si + pop dx + pop cx + pop bx + pop ax + ret +HiAlloc endp +; + page +;****************************************************************************** +; +; HiSysAlloc - allocate hi system memory - update hi memory control words +; +; entry: REAL or VIRTUAL MODE +; DS pts to DGROUP +; ax = # of 4k byte pieces to allocate +; +; exit: If enough hi system memory available +; update available hi system memory. +; ax = # of 4k byte pieces used before this allocation. +; CY cleared +; else +; ax = amount of hi system memory available +; CY set +; If error occurs in writing control words, +; CY set +; ax = -1 +; +; used: see above +; +; stack: +; +;****************************************************************************** + assume cs:LAST, ds:DGROUP, es:NOTHING +HiSysAlloc proc near + push bx + push es +; + push ax ; save amount asked for + mov bx,X_HI_MEM_SEG ; high memory segment + mov es,bx + mov bx,es:X_HI_PTR ; pointer to high memory control words + mov ax,es:[bx+X_HISYS] ; ax = amount of hi system mem available + and ax,00ffh ; after we get rid of high byte + pop bx ; bx = amount requested + ; ax = amount currently available + cmp ax,bx ; Q: available >= requested? + jb Hisys_xit ; N: quit - carry set => not enough mem + add [hisys_alloc],bx ; Y: save it in case we must deallocate + push ax ; save amount available before + xor ax,ax ; ax = no hi user mem to alloc + call HImod ; go allocate high sys mem + pop bx ; bx = amount available before + jc Hisys_err ; MOD ERROR -> set error flag + mov ax,10h ; 16 pages in high sys mem pool + sub ax,bx ; ax = amount used before this request + jmp Hisys_xit ; no error in move block +; +Hisys_err: + mov ax,-1 + stc ; to be sure +Hisys_xit: + pop es + pop bx + ret +HiSysAlloc endp +; + page +;****************************************************************************** +; +; Himod - allocate/deallocate hi memory - update hi memory control words +; +; entry: REAL or VIRTUAL MODE +; DS pts to DGROUP +; ax = size in 16 bytes of hi USER mem to alloc (a negative # +; will deallocate) +; bx = size in 4k bytes of hi SYSTEM mem to alloc (ditto above) +; +; exit: update available hi memory and last used address. +; ax = New last used address for high user memory +; CY = set if block move error occurred +; +; used: none +; +; stack: +; +;****************************************************************************** + assume cs:LAST, ds:DGROUP, es:NOTHING +HImod proc near + push bx + push cx + push dx + push si + push es +; + call UnLockROM ;Q: ROM space writeable? + jz unlock_ok ; Y: continue + jmp Himod_err ; N: exit +unlock_ok: + push bx ; save hi system memory allocation + mov bx,X_HI_MEM_SEG ; high memory segment + mov es,bx + mov bx,es:X_HI_PTR ; pointer to high memory control words + sub es:[bx+X_AVAIL_MEM],ax ; update hi memory available + sub es:[bx+X_LAST_HI],ax ; and last used address + pop ax ; get hi system memory amount + sub es:[bx+X_HISYS],ax ; update hi system memory available + mov ax,es:[bx+X_LAST_HI] ; start of this hi memory +; + call LockROM ;Q: ROM write protected now ? + clc ; clear error flag + jz Himod_xit ; Y: exit with no error +; ; N: report error +Himod_err: + stc ; indicate error +HImod_xit: + pop es + pop si + pop dx + pop cx + pop bx +; + ret + + +HImod endp + page +;****************************************************************************** +; +; LockROM - write protects high system RAM +; +; entry: REAL or VIRTUAL MODE +; DS pts to DGROUP +; +; exit: Z = no error - high system RAM write protected +; NZ = ERROR. +; +; used: none +; +; stack: +; +;****************************************************************************** + assume cs:LAST, ds:DGROUP, es:NOTHING +LockROM proc near + push ax ; save ax + push cx + push dx + push es +; + mov word ptr [buffer],LOCK_ROM ; word to write to unlock + jmp UL_write ; go write it... +; +LockROM endp + + page +;****************************************************************************** +; +; UnLockROM - turns off write protect on high system RAM +; +; entry: REAL or VIRTUAL MODE +; DS pts to DGROUP +; +; exit: Z = no error - high system RAM writeable +; NZ = ERROR. +; +; used: none +; +; stack: +; +;****************************************************************************** + assume cs:LAST, ds:DGROUP, es:DGROUP +UnLockROM proc near + push ax ; save ax + push cx + push dx + push es +; + mov word ptr [buffer],UNLOCK_ROM ; word to write to unlock +; +UL_write: + mov ax,seg DGROUP ; set source addr to buffer + mov es,ax ; set ES to DGROUP + mov cx,16 + mul cx ; make 24 bits + add ax,offset DGROUP:buffer + adc dl,0 + mov cx,1 ; 1 word to transfer + call set_src_selector ; set source segment selector to buffer + mov ax,LOCK_ADR_LO ; DX:AX = 32-bit addr of ROM LOCK + mov dx,LOCK_ADR_HI + mov cx,1 ; 1 word long + call set_dest_selector ; destination is unlock address + + mov ax,seg LAST + mov es,ax ; es to last segmetn + mov si,offset DGROUP:gdt_mb ; ES:SI -> global descriptor table + mov ah,MOVE_BLK ; int 15 block move function code + int XBIOS ; unlock rom + or ah,ah ; Q: error? + ; Y: return NZ + ; N: return Z + pop es + pop dx + pop cx + pop ax + ret +UnLockROM endp ; end of procedure + +endif ; end of code for not NOHIMEM + + +;****************************************************************************** +; +; OEM_Init_Diag_Page: Initialise the 5th page table to point to the +; diagnostic segment. +; +; description: +; +; place 32 bit memory board diagnostic byte address into page table +; xxxx0000h - xxxxFFFFh physical +; -> 01000000h - 0100FFFFh linear => 64k => 16 entries in page tables +; => 1st 64k in 5th page table +; +; entry: DS pts to DGROUP +; ES:0 Page table seg. +; +; exit: nothing +; +; used: ax,di,dx,bx,cx,flags +; +; stack: +; +;****************************************************************************** +; +OEM_Init_Diag_Page proc near + assume cs:LAST, ds:dgroup, es:NOTHING +; +; + mov di,4*P_SIZE ; ES:DI -> 1st 64k of 5th page table + mov dx,OEM_MEM_HI + xor ax,ax ; start with physical addr = xxxx0000h + mov bh,0 + mov bl,P_AVAIL ; make pages available to all + mov cx,10h ; set 64k worth of entries +IT_set_entry: + call SetPageEntry + ; ES:[DI] pts to next page table entry + add ax,1000h ; next physical page + adc dx,0h ; address in DX,AX + loop IT_set_entry ;Q: done with page table entries ? + ; N: loop again + ; Y: all done + ret +; +OEM_Init_Diag_Page endp + +LAST ends ; End of segment + +ifndef NOHIMEM ; if high memory in this model + +R_CODE SEGMENT + assume cs:R_CODE, ds:DGROUP, es:DGROUP + +;****************************************************************************** +; InitLock - Init state of Table lock +; +; NOTE: this is a FAR routine. +; +; ENTRY: REAL MODE +; DS = DGROUP +; +; EXIT: REAL MODE +; DGROUP:[DiagByte] = updated to current LOCK state +; +; USED: AX,BX +; +;****************************************************************************** +InitLOCK proc far + + mov [DiagByte],LOW LOCK_ROM ; default is locked + push es + mov ax,X_HI_MEM_SEG + mov es,ax ; ES -> ROM + mov bx,X_MT_386 ; ES:BX -> machine type byte + mov ax,ES:[bx] ; AX = ROM contents + xor ES:[bx],0FFFFh ; flip all bits in ROM + xor ax,0FFFFh ; AX = "flipped" value + cmp ax,ES:[bx] ;Q: flipped value in ROM ? + jne gv_locked ; N: "ROM" is locked + mov [DiagByte],LOW UNLOCK_ROM ;Y: ROM is UNLOCKED +gv_locked: + xor ES:[bx],0FFFFh ; restore ROM contents (if changed) +; + pop es + ret + +InitLOCK endp + +R_CODE ENDS + +endif ; end of code for not NOHIMEM + + end ; of module + diff --git a/v4.0/src/MEMM/MEMM/PAGE.INC b/v4.0/src/MEMM/MEMM/PAGE.INC new file mode 100644 index 0000000..aa76e69 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/PAGE.INC @@ -0,0 +1,52 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: PAGE.INC - Definitions for paging on 386 +; +; Version: 0.02 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +; +; Functional Description: +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +P_SIZE equ 1000h ; page size + +P_PRES equ 01h ; page present bit +P_WRITE equ 02h ; write access bit +P_USER equ 04h ; access bit for User mode +P_ACC equ 10h ; page accessed bit +P_DIRTY equ 20h ; page dirty bit + + +P_AVAIL equ (P_PRES+P_WRITE+P_USER) ; avail to everyone & present + +PAGE_ENTRY macro addr,stat + dd addr ; access & status in low 12 + ; address in high 20 +endm + +.list ; end of PAGE.INC diff --git a/v4.0/src/MEMM/MEMM/PIC_DEF.EQU b/v4.0/src/MEMM/MEMM/PIC_DEF.EQU new file mode 100644 index 0000000..93706b5 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/PIC_DEF.EQU @@ -0,0 +1,78 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: PIC_DEF.EQU - 8259 programmable interrupt controllers +; +; Version: 0.02 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 05/12/86 B Cleanup and segment reorganization +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif +; +; Master interrupt controller parameters +; +PIC1_CMD = 20H ; 8259A command register. +PIC1_INIT = 21H ; 8259A initialization register. +PIC1_STAT = 20H ; 8259A status (who interrupted) +PIC1_MASK = 21H ; 8259A operation control word #1. +; +PIC1_ICW1_VAL = 11H ; Edge trig, 8 interval, cascade, ICW4. +PIC1_ICW2_VAL = 08H ; Interrupt vector address. +PIC1_ICW3_VAL = 04H ; Slave id. +PIC1_ICW4_VAL = 01H ; 8088 mode, norm EOI, non-buf, no nest. +; +; Slave interrupt controller parameters +; +PIC2_CMD = 0A0H ; 8259A command register. +PIC2_INIT = 0A1H ; 8259A initialization register. +PIC2_STAT = 0A0H ; 8259A status (who interrupted) +PIC2_MASK = 0A1H ; 8259A operation control word #1. +; +PIC2_ICW1_VAL = 11H ; Edge trig, 8 interval, cascade, ICW4. +PIC2_ICW2_VAL = 70H ; Interrupt vector address. +PIC2_ICW3_VAL = 02H ; Master id. +PIC2_ICW4_VAL = 01H ; 8088 mode, norm EOI, non-buf, no nest. +; +MASK_DISABLE = 0FFH ; Mask register, no levels allowed. +READ_ISR = 0BH ; Command to read PIC In-Service-Reg. +EOI = 20H ; End-Of-Interrupt (non-specific). +; +IRQ0_ENABLE = 11111110B ; Mask to enable IRQ0. +IRQ1_ENABLE = 11111101B ; Mask to enable IRQ1. +IRQ2_ENABLE = 11111011B ; Mask to enable IRQ2. +IRQ3_ENABLE = 11110111B ; Mask to enable IRQ3. +IRQ4_ENABLE = 11101111B ; Mask to enable IRQ4. +IRQ5_ENABLE = 11011111B ; Mask to enable IRQ5. +IRQ6_ENABLE = 10111111B ; Mask to enable IRQ6. +IRQ7_ENABLE = 01111110B ; Mask to enable IRQ7. +; +IRQ8_ENABLE = 11111110B ; Mask to enable IRQ8. +IRQ9_ENABLE = 11111101B ; Mask to enable IRQ9. +IRQ10_ENABLE = 11111011B ; Mask to enable IRQ10. +IRQ11_ENABLE = 11110111B ; Mask to enable IRQ11. +IRQ12_ENABLE = 11101111B ; Mask to enable IRQ12. +IRQ13_ENABLE = 11011111B ; Mask to enable IRQ13. +IRQ14_ENABLE = 10111111B ; Mask to enable IRQ14. +IRQ15_ENABLE = 01111111B ; Mask to enable IRQ15. +; +.list ; end of PIC_DEF.EQU diff --git a/v4.0/src/MEMM/MEMM/PPAGE.ASM b/v4.0/src/MEMM/MEMM/PPAGE.ASM new file mode 100644 index 0000000..677c583 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/PPAGE.ASM @@ -0,0 +1,510 @@ + + + page 58,132 +;****************************************************************************** + TITLE PPAGE - MODULE to find mappable Physical pages +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: PPAGE - Find Mappable Physical Pages +; +; Version: 0.01 +; +; Date: Aug 1, 1988 +; +; Author: ISP +; COMMENTS** This routine needs extensive work to do a better +; job of identification of unmappable segments. That +; is why we seem to have a whole lot of procedures +; which don't do much now. +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +;****************************************************************************** +; Functional Description: +; This module initialises the mappable physical pages in memory. +; It also finds a valid page frame for use. +; +;****************************************************************************** +.lfcond +.386p + + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** + + public mappable_segs + public Map_tbl + public max_PF + public find_phys_pages + public exclude_segments + public is_page_mappable + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +FIRST_SYSTEM_ROM_SEG_HI = 0F000h +FIRST_SYSTEM_ROM_SEG_LO = 0E000h +LAST_SYSTEM_ROM_SEG = 0FFFFh +; +FIRST_VIDEO_MEM_SEG = 0A000h +LAST_VIDEO_MEM_SEG = 0BFFFh +; +FIRST_CONV_UMAP_SEG = 00000h +LAST_CONV_UMAP_SEG = 03FFFh + + +;****************************************************************************** +; INCLUDE FILES +;****************************************************************************** + include vdmseg.inc ; segment definitions + include emm386.inc ;contains the error messages + include emmdef.inc ;contains some emm defines + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +; +_DATA segment + + extrn PF_Base:word + extrn msg_flag:word + +_DATA ends + +; +LAST segment +; + extrn rom_srch:near +; +LAST ends + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + + +;****************************************************************************** +; +; Code Segments +; +;****************************************************************************** +; +_TEXT segment +_TEXT ends + +LAST segment + assume cs:LAST, ds:DGROUP, es:DGROUP + + page +;************************************************************************* +; +; initialisation data +; +;************************************************************************* +; table for identifying mappable pages +; +mappable_segs label byte + db TOT_PHYS_PAGES dup(PAGE_MAPPABLE) ; +; +; table for PF base addresses +; +Map_tbl label word + dw 0c000h + dw 0c400h + dw 0c800h + dw 0cc00h + dw 0d000h + dw 0d400h + dw 0d800h + dw 0dc00h +max_PF equ (this byte - Map_tbl) + dw 0e000h + + page +;****************************************************************************** +; find_phys_pages: routine to find mappable phsyical pages and a page fr +; +; ENTRY: PF_base set to -1 (user didn't specify apge frame) +; or offset into Map_tbl +; EXIT: mappable_segs array initalised to indicate mappable pages +; first_system_page initialised +; num_system_pages initialised +; PF_Base initalised to page frame +; [msg_flag] set if error to error message number +; USED: none +; +;****************************************************************************** +find_phys_pages proc near +; +; start out with all the pages initialised to be mappable except those excluded +; by explicit instruction of the command line. +; + +; +; exclude segments in the lo end of system memory +; + call exclude_conv_RAM + +; exclude segments in the system ROM area +; + call exclude_system_ROM + +; +; exclude segments in the video area +; + call exclude_video_mem + +; +; then search for option rom's in the area C000 to E000 and exclude the +; segments in which option rom exists. +; + call rom_srch ; this searches for option rom's and + ; removes the segments of these from + ; being mappable +; +; then find the page frame from the information of mappable segs from C000-E000 +; and the user specified page frame (if any). +; + call find_pf_base +; +; and then exit +; + ret +; +find_phys_pages endp + + page +;****************************************************************************** +; find_pf_base: routine to find a valid page frame +; +; ENTRY: PF_base set to -1 (user didn't specify apge frame) +; or index into Map_tbl +; ax = index into Map_tbl from rom_srch on a possible pageframe. +; +; EXIT: PF_base set to page frame segment (C000..E000) on no error +; If error msg_flag set to appropriate error message +; +; USES: NONE +; +;****************************************************************************** +find_pf_base proc near +; + push ax + push bx + push cx + push si +; +; we have to examine all the possible page frames by looking at the entries +; for the page frame in the mappable_segs array and find all possible page +; frames. the first such valid page frame found is remembered +; + + ; + ; initialise + ; + mov ax,0ffffh ; first possible page frame + xor bx,bx ; index into map_tbl + ; + ; outer loop entry. check for loop termination + ; +examine_map_tbl_loop: + ; + cmp bx,MAX_PF ; are we done + ja choose_PF ; yes, go to choose page frame + ; + ; get the page frame segment. convert to phys. page # + ; + mov si,cs:Map_Tbl[bx] ; + shr si,10 + ; + ; examine the entries for the 4 pages comprising this segment + ; + mov cx,4 +check_pages_loop: + cmp cs:mappable_segs[si],PAGE_MAPPABLE + jne invalidate_PF + inc si + loop check_pages_loop + + ;***SUCCESS + + ; + ; exit point. pf is valid. see if we already have a pf. if not we store + ; this. + ; + cmp ax,0ffffh ; do we have a pf already? + jne skip_get_PF ; skip if we do + mov ax,bx ; else store +skip_get_PF: + ; + ; go to examine next PF + ; + jmp next_PF + + ;***FAILURE + + ; + ; exit point. pf is invalid. remove it from map_tbl + ; +invalidate_PF: + mov cs:Map_Tbl[bx],0ffffh ; + ; + ;***SETUP TO LOOP AGAIN +next_PF: + ; + add bx,2 + jmp examine_map_tbl_loop +; +choose_PF: +; +; Choosing a page frame. If the user has specified a page frame then +; validate it else give him the page frame we found first. +; + ; + ; has the user specified a pf. if so go to validate it + ; + cmp [PF_Base],0ffffh ; + jne def_cont2 + ; + ; user didn't specify a pf. did we find a pf. if so give it else indicate + ; error + ; + cmp ax,0ffffh ; did we find one + je no_PF_warn ; if not go to warn the user + mov bx,ax + mov ax, cs:Map_Tbl[bx] ; get the PF + mov [PF_Base],ax ; + or [msg_flag],BASE_ADJ_MSG ; + jmp pf_xit + + ; + ; we don't have a pf. warn the user + ; +no_PF_warn: + or [msg_flag],NO_PF_MSG + jmp pf_xit +; +; they specified a base address. Let's make sure it's good +; +def_cont2: + mov bx,[PF_Base] ; get the offset they specified + mov ax,bx ; ax = bx + shr ax,1 ; back to 0..8 + mov cx,0400h ; length of PF segments + mul cx ; addr = 0c000h + (Mx-1)*400h + add ax,0c000h + mov [PF_Base],ax ; save it + + cmp cs:Map_tbl[bx],0ffffh ; Is this any good? + jne pf_xit ; probably + or [msg_flag],PF_WARN_MSG ; probably not +; +; we need to ensure that the pages corresponding to the page frame are forced +; into being mappable. this is necessary because we accept the user's discretio +; in forcing a page frame in a certain area. +; + mov si,ax ; segment + shr si,10 ; phys page# + mov cx,4 +force_PF_pages: + mov cs:mappable_segs[si],PAGE_MAPPABLE + inc si + loop force_PF_pages + +pf_xit: + pop si + pop cx + pop bx + pop ax + ret + +find_pf_base endp + + +;***********************************************************************; +; exclude_video_mem ; +; ; +; Excludes the segments between A000 and C000. ; +; ; +; input: none ; +; ; +; returns: none ; +; ; +; uses: ; +; ; +; calls:exclude_segments ; +; ; +; History: ; +; ISP (isp). Wrote it. ; +;***********************************************************************; +exclude_video_mem proc near +; + push bx + push ax +; + mov bx,FIRST_VIDEO_MEM_SEG + mov ax,LAST_VIDEO_MEM_SEG + call exclude_segments +; + pop ax + pop bx + ret +; +exclude_video_mem endp + +;***********************************************************************; +; exclude_system_ROM ; +; ; +; Excludes the segments between A000 and C000. ; +; ; +; input: none ; +; ; +; returns: none ; +; ; +; uses: ; +; ; +; calls:exclude_segments ; +; ; +; History: ; +; ISP (isp). Wrote it. ; +;***********************************************************************; +exclude_system_ROM proc near +; + push bx + push ax +; +ifndef NOHIMEM + mov bx,FIRST_SYSTEM_ROM_SEG_LO +else + mov bx,FIRST_SYSTEM_ROM_SEG_HI +endif + + mov ax,LAST_SYSTEM_ROM_SEG + call exclude_segments +; + pop ax + pop bx + ret +; +exclude_system_ROM endp + +;***********************************************************************; +; exclude_conv_RAM ; +; ; +; Excludes segments between 0000 and 4000h ; +; ; +; inputs:none ; +; ; +; returns: none ; +; ; +; History: ; +; ISP (isp). Wrote it +;***********************************************************************; +exclude_conv_RAM proc near +; + push bx + push ax +; + mov bx,FIRST_CONV_UMAP_SEG + mov ax,LAST_CONV_UMAP_SEG + call exclude_segments +; + pop ax + pop bx + ret +; +exclude_conv_RAM endp + +;-----------------------------------------------------------------------; +; exclude_segments ; +; ; +; Excludes the given segments from the memory map. ; +; ; +; Arguments: ; +; AX = high segment ; +; BX = low segment ; +; Returns: ; +; nothing ; +; Alters: ; +; AX,BX ; +; Calls: ; +; nothing ; +; History: ; +; ISP (isp). modified from ps2emm sources. ; +;-----------------------------------------------------------------------; +exclude_segments proc near +; + push cx + push es + push di +; +; fix the segments to form physical page numbers +; + mov cl,10 ; to convert segment to physical page # + shr ax,cl + shr bx,cl + sub ax,bx + jb exclude_segments_done + inc ax + mov cx,ax +; +; get addressing into mappable_segs array +; + push cs + pop es + assume es:nothing + lea di, mappable_segs[bx] + mov al,PAGE_NOT_MAPPABLE + cld + rep stosb +exclude_segments_done: +; + pop di + pop es + pop cx + ret +; +exclude_segments endp + +;-----------------------------------------------------------------------; +; is_page_mappable ; +; ; +; specifies whether a given physical page is mappable or not. ; +; ; +; Arguments: ; +; si = physical page ; +; Returns: ; +; ZF set if mappable ; +; ZF clear if not mappable ; +; Alters: ; +; flags ; +; Calls: ; +; nothing ; +; History: ; +; ISP (isp). 8/29/88 ; +;-----------------------------------------------------------------------; +is_page_mappable proc near +; + cmp cs:mappable_segs[si],PAGE_MAPPABLE + ret +; +is_page_mappable endp + +LAST ends ; End of segment +; + + end ; End of module + diff --git a/v4.0/src/MEMM/MEMM/PRINT.ASM b/v4.0/src/MEMM/MEMM/PRINT.ASM new file mode 100644 index 0000000..91d8571 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/PRINT.ASM @@ -0,0 +1,424 @@ + + +page 58,132 +;****************************************************************************** + title PRINT.ASM - Protected Mode Print Routines +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMMD.EXE - MICROSOFT Expanded Memory Manager 386 DEBUG Driver +; +; Module: PRINT.ASM - Protected Mode Print Routines +; +; Version: 0.04 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/05/86 0.04 Moved to DCODE segment +; 07/06/86 0.04 moved data to DDATA segment +; +;****************************************************************************** +; +; Functional Description: +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + + public PrintString + public PrintHex + public kputc + public RowCol + public IsReal + +NAME print + +;** print - cga simple print routines +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + +;*** IsReal - determine mode of cpu +; +; This routine is useful when writing dual mode code. +; It returns with 'Z' = 1 if the cpu is in real mode, +; otherwise 'Z' = 0. +; +; ENTRY DUAL MODE +; +; EXIT 'Z' = 1 (protected mode), 0 (real mode) +; +; USES flags +; +_TEXT segment + + assume cs:_TEXT, ds:nothing, es:nothing, ss:nothing + +IsReal proc near + + push ax + smsw ax + xor al, 0ffh + and al, 1 + pop ax + ret ; returns with flags set + +IsReal endp + +_TEXT ends + +;*** kputc - write character/attribute to screen +; +; This is a simple character output routine. It does not +; interleave writes to video memory with the 6845. It +; does not update the cursor position. It does not understand +; anything except a CGA in 80x25 text mode. +; +; ENTRY PROTECTED MODE +; AX - character-attribute to write +; DS - kernel data selector +; +; EXIT none - character written +; +; USES AX, flags +; + +_DATA segment +RowCol dw 0 +_DATA ends + +CR equ 0dh ; carriage return +LF equ 0ah ; line feed +TAB equ 9 ; tab +BS equ 8 ; backspace + +COLOUR_PARA equ 0b800h + +_TEXT segment + + assume cs:_TEXT, ds:_DATA, es:nothing, ss:nothing + +kputc proc far + + push bx ; save callers regs + push cx + push dx + push si + push di + push es + push ds + + call IsReal ; need dual mode access + jnz kp10 + mov dx, VDMD_GSEL ; selector for protected mode + jmp kp11 +kp10: + mov dx, seg _DATA ; para for real mode +kp11: + push dx ; save this segment for later + + mov ds, dx ; DS -> data segment + mov dx, ds:[RowCol] ; DX = current row/col + + cmp al, CR ; is character a CR? + jne kp1 + + mov dl, 0 ; yes, go to column 0 + jmp kp3 ; jump to common code +kp1: + + cmp al, LF ; is character a LF? + jne kp2 + + inc dh ; yes, go to next row + jmp kp3 ; jump to common code +kp2: + + cmp al, TAB ; is it a tab + jne kp12 + and dl, 0f8h ; mask off low 3 bits (8 ch) + add dl, 8 ; move to next tab position + jmp kp3 ; jmp to common code +kp12: + + cmp al, BS ; is it backspace + jne kp13 + dec dl ; back up one column + jmp kp3 ; goto common code +kp13: +; Must be ordinary character. Write it to screen, update position + + push ax ; save char/attr + + mov al, dh ; AL = row + mov ah, 80 ; multiplier, 80 char per row + mul ah ; AX = cell at start of row + mov bh, 0 + mov bl, dl ; BX = column + add bx, ax ; BX = cell + shl bx, 1 ; BX = byte offset of cell + + call IsReal ; bi-modal access to screen + jnz kp6 + mov ax, COLOUR_GSEL ; screen selector for protected mode + jmp kp7 +kp6: + mov ax, COLOUR_PARA ; screen para for real mode +kp7: + mov es, ax ; ES -> screen + + pop es:[bx] ; write character + inc dl ; update column +kp3: +; Common code, first check for line wrap: + + cmp dl, 80 ; beyond rhs of screen? + jl kp4 + mov dl, 0 ; go to col 0 + inc dh ; and move to next line +kp4: +; Now check for scroll needed: + + cmp dh, 25 ; are we off end of screen? + jl kp5 + +; Now scroll screen + + call IsReal ; bi-modal access to screen + jnz kp8 + mov ax, COLOUR_GSEL ; screen selector for protected mode + jmp kp9 +kp8: + mov ax, COLOUR_PARA ; screen para for real mode +kp9: + mov ds, ax ; DS -> screen + mov es, ax ; ES -> screen + + mov di, 0 ; ES:DI = copy destination + mov si, 160 ; DS:SI = copy source + mov cx, 2000-80 ; copy word count + cld + rep movsw ; scroll + +; Blank bottom line + + mov al, ' ' + mov ah, 7 ; AX = blank character + + mov cx, 80 ; number of cells to blank + mov di, 4000-160 ; ES:DI = start point + rep stosw + +; Update position + + mov dh, 24 ; new row +kp5: + pop ds ; set DS to data again + mov ds:[RowCol], dx ; update row/col + +; call SetCursor + + pop ds ; restore regs + pop es + pop di + pop si + pop dx + pop cx + pop bx + + ret + +kputc endp +_TEXT ends + + +;*** SetCursor - updates cursor position +; +; This routine reprograms the 6845 cursor position, and +; stores the new cursor position in the ROM bios data area. +; +; ENTRY DUAL MODE +; DH, DL = row, col +; +; EXIT cursor updated +; +; USES ax, bx, cx, flags +; + +CRT_COLS equ 04ah +CURSOR_POSN equ 050h +CRT_START equ 04eh +ADDR_6845 equ 063h + +_TEXT segment + + assume cs:_TEXT, ds:_DATA, es:nothing, ss:nothing + +SetCursor proc near + + push ds + mov bx, 40h + mov ds, bx + +; Save new position in BIOS data area + + mov ds:[CURSOR_POSN], dx + +; Calculate offset on screen + + mov al, dh ; row + mul byte ptr ds:[CRT_COLS] ; row * cols + mov bl, dl ; bl = column + mov bh, 0 ; bx = column + add ax, bx ; ax = offset in screen + sal ax, 1 ; double for attribute bytes + mov cx, ds:[CRT_START] ; cx = start point of screen + add cx, ax ; cx = offset of cursor + sar cx, 1 ; convert to char count only + +; Now program 6845 + + mov al, 14 ; 6845 register + mov dx, ds:[ADDR_6845] ; base port # + out dx, al + inc dx + jmp short $+2 + + mov al, ch + out dx, al + dec dx + jmp short $+2 + + mov al, 15 + out dx, al + inc dx + jmp short $+2 + + mov al, cl + out dx, al + + pop ds + + ret + +SetCursor endp +_TEXT ends + + +;*** PrintString - prints a message on console +; +; This routine calls the "kernel" to print a string +; one character at a time. +; +; ENTRY 286 PROTECTED MODE +; DS - DATA3_SEL +; ES - DATA3_SEL +; SI - offset in DS of null terminated string to print +; +; EXIT String printed +; +; USES Flags +; + +_TEXT segment + + assume cs:_TEXT, ds:nothing, es:nothing, ss:nothing + +PrintString proc near + + cld ; set up for string ops + push si ; save callers regs + push ax + +pr1: ; loop printing until null + lodsb ; al = char to print + and al, al ; terminator ? + je pr2 + mov ah, 7 ; attribute + + db 9ah ; far call + dw offset _TEXT:kputc ; offset + dw VDMC_GSEL ; selector + + jmp pr1 ; back for more +pr2: + pop ax ; restore callers regs + pop si + + ret + +PrintString endp + +_TEXT ends + +;*** Hex2String +; +; Convert content of AX into 4 Hex digits string at ES:DI +; +; ENTRY AX value to convert +; ES:DI storage string location +; + +_TEXT segment + + assume cs:_TEXT, ds:nothing, es:nothing, ss:nothing + +PutHexChar proc near + + cmp al,9 + ja PHC_AF + add al,30h + jmp PHC_exit +PHC_AF: + add al,(41h - 0ah) +PHC_exit: + push ax + mov ah,7 + db 9ah ; far call + dw offset _TEXT:kputc ; offset + dw VDMC_GSEL ; selector + pop ax + ret + +PutHexChar endp + +PrintHex proc near + + cld + + xchg al,ah + push ax + shr al,4 + call PutHexChar + pop ax + and al,0fh + call PutHexChar + xchg al,ah + push ax + shr al,4 + call PutHexChar + pop ax + and al,0fh + call PutHexChar + + ret + +PrintHex endp + +_TEXT ends + + end + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/RETREAL.ASM b/v4.0/src/MEMM/MEMM/RETREAL.ASM new file mode 100644 index 0000000..8ffc602 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/RETREAL.ASM @@ -0,0 +1,228 @@ + + +page 58,132 +;****************************************************************************** + title RetReal - Return-To-Real routine(s) for the 386 +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: RetReal - Return-To-Real routine(s) for the 386 +; +; Version: 0.04 +; +; Date: February 20, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 02/20/86 Original +; 05/12/86 A Cleanup and segment reorganization +; 06/01/86 Removed Real386a (loadall version) and left only +; RetReal via PE bit +; 06/21/86 0.02 Saved Eax +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/02/86 0.03 Reset TSS busy bit +; 07/05/86 0.04 Added Real_Seg label for _TEXT fixup +; 07/06/86 0.04 changed assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; +; This module contains the routine RetReal which goes from Ring 0 protected +; mode to Real Mode by resetting the PE bit (and the PG bit). +; +; NOTE: this module only works on the B0 and later parts. The A2 part +; will leave the CS non writeable. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public RetReal + public Real_Seg + + page +;****************************************************************************** +; I N C L U D E F I L E S +;****************************************************************************** + +include VDMSEG.INC +include VDMSEL.INC +include INSTR386.INC +include OEMDEP.INC + +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +_DATA segment + extrn Active_Status:byte +_DATA ends + +_TEXT segment + + extrn SelToSeg:near ; selector to segment (I286) + extrn DisableA20:near ; disable A20 line (MODESW) + +_TEXT ends +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +FALSE equ 0 +TRUE equ not FALSE + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +_TEXT segment + assume cs:_TEXT, ds:DGROUP + +;*** RetReal - cause a 386 mode switch to real mode +; +; ENTRY Ring 0 protected mode +; CLI - interrupts disabled +; NMI should also be disabled here. +ifndef NOHIMEM +; FS = Diag segment selector +endif +; +; EXIT Real Mode +; DGROUP:[Active_Status] = 0 +; CS = _TEXT +; DS = ES = FS = GS = DGROUP +; SS = stack segment +; general registers preserved +; flags modified +; interrupts disabled +; A20 disabled +ifndef NOHIMEM +; high system memory LOCKED +endif +; +; USES see exit conditions above +; +; DESCRIPTION +; +real_gdt label qword +real_idt dw 0FFFFh ; limit + dw 0000 ; base + dw 0000 + dw 0000 ; just in case + + public RetReal +RetReal proc near + PUSH_EAX ; save two scratch registers + push bx + cli ; disable ints + + smsw ax ;check to see if we are in real mode + test ax,1 + jnz rl386_a ;jump if in protected mode + sti + pop bx + POP_EAX + ret ;otherwise return + +rl386_a: + +; +; reset TSS busy bit before returning to Real Mode +; + mov ax, GDTD_GSEL + mov es, ax ; ES:0 = ptr to gdt + + and byte ptr ES:[TSS_GSEL + 5], 11111101B + +; +; lock high system ROM before returning to real +; + HwTabLock + +; +; First save return ss:sp. We have to translate +; the current ss (a selector) into a segment number. +; Calculate a real mode segment corresponding to the +; current protected mode stack selector base address. +; +; We get the base address from the descriptor table, +; and convert it to a paragraph number. +; + mov bx,ss ; bx = selector for stack + call SelToSeg ; AX = segment number for SS + mov bx,ax ; BX = setup stack segment +; +; +; Intel shows DS,ES,FS,GS,and SS set up to make sure 'Real Mode' type +; access rights, and limit are installed. In this program, that happens +; to already be the case, but for general purposeness, VDMD_GSEL fits +; the bill. +; + mov ax,VDMD_GSEL ; selector with real mode attributes + mov ds,ax + mov es,ax + mov ss,ax + MOV_FS_AX + MOV_GS_AX +; +; Intel recommends the following code for resetting the PE bit. Mine +; works OK, but maybe it's not general purpose enough (I was counting +; on knowing that paging wasn't enabled). +; + MOV_EAX_CR0 ; get CR0 + + OP32 + and ax,0FFFEh ; force real mode and shut down paging + dw 07FFFh ; (mov eax,07FFFFFFEh) + + MOV_CR0_EAX ; set CR0 + + ; flush prefetched instructions with: + db 0EAh ; Far Jump opcode + dw offset _TEXT:rl386_b ; destination offset +Real_Seg label word + dw _TEXT ; destination segment +rl386_b: + OP32 ; load up full IDT address + lidt qword ptr cs:[real_idt] + + sti + + MOV_EAX_CR3 ; get CR3 + MOV_CR3_EAX ; set CR3 => clear TLB + + mov ss,bx ; ss = real mode stack segment + mov ax,DGROUP + mov ds,ax + mov es,ax + MOV_FS_AX + MOV_GS_AX + + mov [Active_Status],0 ; rest VDM status + + call DisableA20 ; disable A20 line + + pop bx + POP_EAX + ret ; *** RETURN *** +RetReal endp + +_TEXT ends + end + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/ROMSTRUC.EQU b/v4.0/src/MEMM/MEMM/ROMSTRUC.EQU new file mode 100644 index 0000000..774afb1 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ROMSTRUC.EQU @@ -0,0 +1,37 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: ROMSTRUC.EQU - structure of the option ROM headers. +; +; Version: 0.02 +; +; Date: June 25,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/25/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +OPTION_ROM STRUC +ROM_RECOGNITION DW ? ; HOLDS 0AA55 WORD IF REAL OPTION ROM +ROM_LEN DB ? ; BYTE HOLDING ROM SIZE / 512 +ROM_ENTRY DB ? ; WHERE CODE STARTS IN OPTION ROM +OPTION_ROM ENDS + +.list ; end of ROMSTRUC.EQU diff --git a/v4.0/src/MEMM/MEMM/ROMXBIOS.EQU b/v4.0/src/MEMM/MEMM/ROMXBIOS.EQU new file mode 100644 index 0000000..2ee4418 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ROMXBIOS.EQU @@ -0,0 +1,45 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: ROMXBIOS.EQU - ROM Extra BIOS function calls +; +; Version: 0.02 +; +; Date: June 25,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/25/86 Original +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +XBIOS equ 15h ; Extra BIOS functions + DEV_OPEN equ 80h ; - device open dummy call + DEV_CLOSE equ 81h ; - device close dummy call + PROG_TERM equ 82h ; - program terminate + EVENT_WAIT equ 83h ; - Event Wait + JOYSTICK equ 84h ; - joystick + SYS_REQ equ 85h ; - sys request key routine + UNCOND_WAIT equ 86h ; - unconditional Wait + MOVE_BLK equ 87h ; - move block + EXT_MEM equ 88h ; - extended memory size + ENTER_PROT equ 89h ; - enter protected mode + DEV_WAIT equ 90h ; - Device Wait + DEV_POST equ 91h ; - Device Post + +.list ; end of ROMXBIOS.EQU diff --git a/v4.0/src/MEMM/MEMM/ROM_SRCH.ASM b/v4.0/src/MEMM/MEMM/ROM_SRCH.ASM new file mode 100644 index 0000000..77da48a --- /dev/null +++ b/v4.0/src/MEMM/MEMM/ROM_SRCH.ASM @@ -0,0 +1,317 @@ + + +; + page 58,132 +;****************************************************************************** + title ROM_SRCH - search for option ROMs +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: ROM_SRCH - search for option ROMS and RAM +; +; Version: 0.04 +; +; Date : June 5,1986 +; +; Authors: SP, BT +; +;****************************************************************************** +; +; CHANGES: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------ +; 06/05/86 Original Adapted from ROM code +; 06/25/86 0.02 Fixed upd_map. +; 06/26/86 0.02 Fixed upd_map (again) and ram_srch +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/06/86 0.04 changed assume to DGROUP +; 08/01/88 Updated to identify mappable segs between C000 and E000 +; +;****************************************************************************** + page +;****************************************************************************** +; +; Functional description: +; +; This module contains the code that scans the ROM at the segment +; supplied in register AX looking for ROMs on hardware interface +; boards. The layout of each valid ROM is as follows: +; +; OFFSET +-----------------------+ +; 0 | 55h | +; +-----------------------+ +; 1 | AAh | +; +-----------------------+ +; 2 | ROM size / 512 | +; +-----------------------+ +; 3 | Start of init code | +; : +; n-1 | | +; +-----------------------+ +; (Sum of all bytes MOD 100h is 00h.) +; +; This module also contains the code to search and vector to VDU +; roms (C000:0 to C000:7800 in 2K increments). +; +;****************************************************************************** + page +.386P +; +;****************************************************************************** +; Public Declarations +;****************************************************************************** +; + public rom_srch ; Search and Vector to option ROMs. +;****************************************************************************** +; Externs +;****************************************************************************** +LAST segment + extrn Map_tbl:word + extrn max_PF:abs + extrn mappable_segs:byte + extrn exclude_segments:near + +LAST ends +; +;****************************************************************************** +; Equates +;****************************************************************************** +; +FIRST_ROM = 0C800H ; Segment address of first option ROM. +LAST_ROM = 0EF80H ; Segment address of last option ROM. +FIRST_VDU_ROM = 0C000H ; Seg address of first VDU option ROM. +LAST_VDU_ROM = 0C780H ; Seg address of last VDU option ROM. +FIRST_RAM = 0C000H ; Seg address of 1st possible RAM addr +LAST_RAM = 0EF80H ; Seg addr of last possible RAM addr +NOT_FOUND_INCR = 0800H ; Amount to skip if no ROM found. +; + include emmdef.inc + include vdmseg.inc + include romstruc.equ ; Option ROM structure. +PF_LENGTH equ 0400h ; length of a page frame (*16) +; +;****************************************************************************** +; S E G M E N T S +;****************************************************************************** +LAST segment + ASSUME CS:LAST, DS:DGROUP +; + page +;****************************************************************************** +; +; ROM_SRCH - Search for option ROMs. +; +; This section of code searches the auxiliary rom area (from C8000 up +; to E0000) in 2K increments. A ROM checksum is calculated to insure +; that the ROMs are valid. Valid ROMs must have the 1st byte = 55H +; and the next byte = 0AAH. The next byte indicates the size of the +; ROM in 512-byte blocks. The sum of all bytes in the ROM, modulo 256, +; must be zero. +; +; If a ROM is not found at a location, the next location 2K-bytes down +; is examined. However, if it is found, the next location after this +; ROM is tried. The next ROM location is determine according to the +; size of the previous ROM. +; +; +;****************************************************************************** +rom_srch proc near ; Entry point. + push bx +; +; search for option ROMs +; + mov ax,FIRST_ROM ; Segment address of first option ROM. + cld ; Set direction flag. +nxt_opt: + call opt_rom ; Look for option ROM. + jnc not_fnd1 ; No ROM here + call upd_seg +not_fnd1: + cmp ax,LAST_ROM ;Q: All ROMs looked at ? + jbe nxt_opt ; No, keep looking + ; Y: check for VDU roms +; +; search for VDM ROMs +; + mov ax,FIRST_VDU_ROM ; segment addr for first vdu ROM + cld +nxt_vdu: + call opt_rom ; Q:is it there + jnc not_fnd2 ; No ROM here + call upd_seg +not_fnd2: + cmp ax,LAST_VDU_ROM ;Q: last VDU ROM ? + jbe nxt_vdu ; N: continue + ; Y: check for RAM +; +; search for RAM +; + mov ax,FIRST_RAM ; first seg addr for RAM search + cld +nxt_ram: + call ram_srch ;Q: RAM here ? + jnc not_fndr ; N: check again ? + call upd_seg +not_fndr: + cmp ax,LAST_RAM ;Q: last RAM location + jbe nxt_ram ; N: continue searching + ; Y: all done +; + pop bx + ret +rom_srch endp + page +; +;****************************************************************************** +; OPT_ROM - This routine looks at the ROM located at the segment address +; specified in AX to see if 0TH and 1ST Bytes = 0AA55H. +; If so, it calculates the checksum over the length of +; ROM. If the checksum is valid it updates AX to point +; to the location of the next ROM. +; +; Inputs: AX = Segment address of ROM. +; +; Outputs: CY = Found a VDU ROM at this location. +; NC = Did not find a valid ROM at this location. +; AX = Segment address of next ROM location. +; DX = Length of this ROM +; +;****************************************************************************** +; +opt_rom proc near + push bx + push cx + push si + push ds +; + mov ds,ax ; DS=ROM segment address. + xor bx,bx ; Index uses less code than absolute. + cmp [bx.ROM_RECOGNITION],0AA55H ;Q: Looks like a ROM? + jne rs_3 ; No, Skip down +; +; Compute checksum over ROM. +; + xor si,si ; DS:SI=ROM Pointer; Start at beg. + xor cx,cx ; Prepare to accept byte into word. + mov ch,[bx.ROM_LEN] ; CH=byte count/512 (CX=byte count/2) + shl cx,1 ; CX=adjusted byte count. + mov dx,cx ; Extract size. +rs_2: + lodsb ; MOV AL,DS:[SI+]; Pickup next byte. + add bl,al ; Checksum += byte(SEG:offset) + loop rs_2 ; Loop doesn't affect flags. + jnz rs_3 ; Jump down if bad checksum. +; + mov cl,4 ; Shift of 4... + shr dx,cl ; Converts bytes to paragraphs (D.03) + mov ax,ds ; Replace segment in AX. + add ax,dx ; increment segment by this amount + stc ; rom found + jmp short rs_exit ; Continue. +; +rs_3: + mov dx,(NOT_FOUND_INCR shr 4) ; Prepare for next ROM. + mov ax,ds ; Replace segment in AX. + add ax,dx ; Increment segment. + clc ; no rom found +; +rs_exit: + pop ds + pop si + pop cx + pop bx + ret ; *** RETURN *** +; +opt_rom endp + page +; +;****************************************************************************** +; RAM_SRCH - This routine looks at the address range potentially used +; by the Page Frame to determine if any RAM is in the way. +; It updates the map accordingly. +; +; Inputs: AX = Segment address for RAM search. +; +; Outputs: CY = Found RAM at this location. +; NC = Did not find RAM at this location. +; AX = Segment address of next RAM location. +; DX = Length of this RAM +; +;****************************************************************************** +; +ram_srch proc near + + push bx + push ds +; +; search for RAM +; + xor dx,dx ; length = 0 +ram_loop: + mov ds,ax + add ax,(NOT_FOUND_INCR shr 4); prepare for next chunk + mov bx,ds:0 ; get a word + xor ds:0,0FFFFh ; flip all bits + xor bx,0FFFFh ; BX = "flipped" value + cmp bx,ds:0 ;Q: "flipped" value written out ? + jne no_more_ram ; N: not RAM - leave + xor ds:0,0FFFFh ; Y: is ram, flip bits back + add dx,(NOT_FOUND_INCR shr 4); increment length count + cmp ax,LAST_RAM ;Q: last RAM location ? + jbe ram_loop ; N: continue searching + mov ds,ax ; Y: no more searching +no_more_ram: +; + mov ax,ds ; get current segment + or dx,dx ;Q: any RAM found ? + jnz ram_found ; Y: set RAM found & chk DS seg again + clc ; N: set no RAM + add ax,(NOT_FOUND_INCR shr 4) ; AX -> next one to check + jmp short ram_exit ; and leave +; +ram_found: + stc +ram_exit: + pop ds + pop bx +; + ret +ram_srch endp + page +; + +;****************************************************************************** +; UPD_SEG - This routine looks at the address range used by the ROM/RAM +; that was found to determine how many potential physical +; pages are invalidated from being mappable. It updates +; the mappable_segs array appropriately. +; +; Inputs: AX = Segment address of next ROM/RAM position. +; DX = Length of ROM/RAM +; +; Outputs: [mappable_segs] updated. +; +; Written: 8/1/88 ISP +; Modif: 8/25/88 ISP to make use of exclude_segments +;****************************************************************************** +upd_seg proc near +; + push bx + push ax +; + mov bx,ax + sub bx,dx ; bx now has the first segment of the area + dec ax ; and ax has the last segment of the area +; + call exclude_segments +; + pop ax + pop bx + ret +upd_seg endp +LAST ENDS + END diff --git a/v4.0/src/MEMM/MEMM/RRTRAP.ASM b/v4.0/src/MEMM/MEMM/RRTRAP.ASM new file mode 100644 index 0000000..c1bb1a7 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/RRTRAP.ASM @@ -0,0 +1,436 @@ + + +page 58,132 +;****************************************************************************** + title RRTRAP.ASM - Return To Real Trap +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: RRTRAP.ASM - Return to Real Trap +; +; Version: 0.04 +; +; Date: June 1, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/01/86 Original +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/03/86 0.03 Changed to P84/85 Handlers +; 07/06/86 0.04 Moved JumpReal to R_CODE and far label +; 07/06/86 0.04 Changed assume to DGROUP +; +;****************************************************************************** +; +; Functional Description: +; This module traps ports 85h and 84h and watches for an application +; to output the Return-to-Real code to these ports. If a 84h=0Fh is output, +; then 85h=0h is output, the code in this module returns the system +; to real mode. +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page + +;****************************************************************************** +; I N C L U D E F I L E S +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + include INSTR386.INC + include VM386.INC +; +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +; + public RRP_Handler + public RR_Trap_Init + public RRProc + public JumpReal +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +; +_TEXT segment +extrn RetReal:near +extrn PortTrap:near +_TEXT ends + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +; +FALSE equ 0 +TRUE equ not FALSE + +RR85_Value equ 00h +RR84_Value equ 0Fh + +FLAGS_IF equ 0200h +FLAGS_TF equ 0100h + +RR_MASK equ NOT (FLAGS_IF+FLAGS_TF) ; mask off IF and TF bits + +RTC_CMD equ 70h ; real time clock command port +DISABLE_NMI equ 80h ; cmd to disable NMI +ENABLE_NMI equ 00h ; cmd to enable NMI + +; +;****************************************************************************** +; D A T A S E G M E N T D E F I N I T I O N S +; +ABS0 segment at 0000h +ABS0 ends +; +_DATA segment +RR_Last db 0 ; last RR port trapped +RR85save db 0FFh +RR84save db 0FFh +_DATA ends + +; +;------------------------------------------------------------------------------ +; _TEXT code +;------------------------------------------------------------------------------ +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP + + page +;****************************************************************************** +; RRP_Handler - I/O Trap handler for return to real ports 84h and 85h +; +; ENTRY: Protected Mode Ring 0 +; AL = byte to output to port. +; BX = 2 * port addr +; DX == 0 => input +; <> 0 => output +; DS = DGROUP +; SS:SP pts to: IP, saved DS, saved DX, IP , +; saved DX,saved BX,saved ESI,saved EBX,saved EBP, +; then GP fault stack frame with error code. +; SS:BP = points to stack frame on entry to GP fault handler +; +; EXIT: Protected Mode Ring 0 +; CLC => I/O emulated. +; STC => I/O NOT emulated. +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +RRP_Handler proc near + or dx,dx ;Q: Output ? + jz RRP_Bye ; N: then leave + cmp bx,84h*2 + je P84_Handler ; Process port 84h + cmp bx,85h*2 + je P85_Handler ; Process port 85h +RRP_Bye: + stc ; don't bother to emulate it + ret +RRP_Handler endp + +;****************************************************************************** +; P84_Handler - I/O Trap handler for port 84h +; +; ENTRY: Protected Mode Ring 0 +; AL = byte to output to port. +; BX = 2 * port addr +; DX == 0 => input +; <> 0 => output +; DS = DGROUP +; SS:SP pts to: IP, saved DS, saved DX, IP , +; saved DX,saved BX,saved ESI,saved EBX,saved EBP, +; then GP fault stack frame with error code. +; SS:BP = points to stack frame on entry to GP fault handler +; +; EXIT: Protected Mode Ring 0 +; CLC => I/O emulated. +; STC => I/O NOT emulated. +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +P84_Handler proc near +; + mov [RR84save],al ; Y: save value written to 84 + mov [RR_Last],84h ; save this RR port # + stc ; don't bother to emulate it + ret +; +P84_Handler endp + + page +;****************************************************************************** +; P85_Handler - I/O Trap handler for port 85h +; +; ENTRY: Protected Mode Ring 0 +; AL = byte to output to port. +; BX = 2 * port addr +; DX == 0 => input +; <> 0 => output +; DS = DGROUP +; SS:SP pts to: IP, saved DS, saved DX, IP , +; saved DX,saved BX,saved ESI,saved EBX,saved EBP, +; then GP fault stack frame with error code. +; SS:BP = points to stack frame on entry to GP fault handler +; +; EXIT: If output to 85h => return to Real +; RRTrap emulates the output to 85h +; RRTrap returns to real, fixes the segments and stack, and +; returns to the instruction past the output in real mode. +; If output does not imply return to Real +; Protected Mode Ring 0 +; CLC => I/O emulated. +; STC => I/O NOT emulated. +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +P85_Handler proc near +; + mov [RR85save],al ; Y: save value for 85h + cmp al,RR85_Value ; Q: return to real value output to 85 ? + jne P85_Exit ; N: save port # and leave + cmp [RR_Last],84h ; Y: Q: was last 84h last RR port output ? + jne P85_Exit ; N: save port # and leave + cmp [RR84Save],RR84_Value ; Y: Q: was 84h value RR value ? + jne P85_Exit ; N: save port # and leave + out 85h,al ; Y: emulate output and + jmp RR_GoReal ; return to real(we're in real) +P85_Exit: + mov [RR_Last],85h ; save this RR port addr + stc ; don't bother to emulate it + ret +; +P85_Handler endp + + page +;****************************************************************************** +; RR_GoReal - return client to real after 84/85 trap +; +; This is the return to real code. First we return to real mode. +; Then we set up the stack, restore the registers and return to +; the instruction following the out to 85h. +;************** +;NOTE: the following depends on the entry stack for P85_Handler +; the same. +; ENTRY: +; SS:SP pts to: IP, saved DS, saved DX, IP , +; saved DX,saved BX,saved ESI,saved EBX,saved EBP, +; then GP fault stack frame with error code. +;************** +;****************************************************************************** +; +RR_GoReal: + push ax + mov al,DISABLE_NMI + out RTC_CMD,al ; disable NMIs + pop ax + + call RetReal ; return to real mode, DS,ES = DGROUP +; +; now start resetting registers from the stack +; +; + add sp,8 ; skip IP,DS,DX, and IP + pop dx + pop bx ; last pushed by OUT emulator +; +; now back to stack presented by VmFault's jmp to instr handler +; +; on to JumpReal code and continue in Real mode +; + jmp FAR PTR JumpReal + +;****************************************************************************** +; +; RRProc Force processor into real mode +; +; entry: +; +; exit: Processor is in real mode +; +; used: AX +; +; stack: +; +;****************************************************************************** +RRProc proc near + pushf + cli ; protect this sequence + mov al,RR84_Value ; + out 84h,al ; port 84/85 return to real + mov al,RR85_Value ; sequence ... + out 85h,al ; + jmp $+2 ; clear prefetch/avoid race cond + popf + ret +RRProc endp + +;****************************************************************************** +; +; RR_Trap_Init Initialize data structure for return to real trapping +; +; description: This routine is called when the processor is put in +; virtual mode. It should initialize anything that is +; used by the RRTrap code. It assumes that the handler +; addresses for ports 84h and 85h in IOTrap_Tab are set +; up to point to RRP_Handler. +; +; entry: DS pts to DGROUP +; +; exit: Return to real trapping data structure initialized +; +; used: AX, BX +; +; stack: +; +;****************************************************************************** +RR_Trap_Init proc near + mov [RR_Last],0 ; reset Return to real trap vars + mov [RR85save],0FFh + mov [RR84save],0FFh + mov bh, 00h ; only set for 0084h and 0085h + mov ax, 84h + call PortTrap ; set traps on both return to real + mov ax, 85h ; ports in case client tries to + call PortTrap ; return to real + ret +RR_Trap_Init endp + +_TEXT ends ; end of segment + +;------------------------------------------------------------------------------ +; R_CODE code +;------------------------------------------------------------------------------ +R_CODE segment + assume cs:R_CODE, ds:DGROUP, es:DGROUP, ss:DGROUP +; +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** +; +RR_Jump label dword ; ret addr for instr after out 84 +RR_JOff dw 0 +RR_JSeg dw 0 + +RR_DS dw 0 ; DS for return +RR_SS dw 0 ; SS for return +RR_SP dw 0 ; SP for return + +RR_Flags dw 0 ; low word of flags for return + +;****************************************************************************** +; +; NAME: JumpReal - jump into faulting code and continuing executing in Real +; mode. When a virtual mode process causes a GP fault, then wishes +; to continue executing in Real mode afterwards, VDM returns to real +; mode then calls this routine to "unwind" the stack and continue +; the process in real mode. +; +; THIS IS A FAR JUMP *** +; +; ENTRY: REAL MODE +; SS:[BP] -> points to GP fault stack frame +; SS:[SP] = saved client's ESI +; SS:[SP+4] = saved client's EBX +; SS:[SP+8] = saved client's EBP +; +; EXIT: REAL MODE +; continues execution of process specified in GP fault stack +; frame. +; +;****************************************************************************** +JumpReal label far + push cs + pop ds ; set DS= CS = R_CODE + ASSUME DS:R_CODE + ; set up return address + mov bx,[bp.VTFOE+VMTF_EIP] ; get return IP + mov [RR_JOff],bx ; save it + mov bx,[bp.VTFOE+VMTF_CS] ; get return CS + mov [RR_JSeg],bx ; save it +; + mov bx,[bp.VTFOE+VMTF_EFLAGS] ; get flags + mov [RR_Flags],bx ; and save + and [bp.VTFOE+VMTF_EFLAGS],RR_MASK ; mask off certain bits +; + mov bx,[bp.VTFOE+VMTF_DS] ; get DS + mov [RR_DS],bx ; save it + + mov bx,[bp.VTFOE+VMTF_SS] ; get SS + mov [RR_SS],bx ; save it + mov bx,[bp.VTFOE+VMTF_ESP] ; get SP + mov [RR_SP],bx ; save it +; +; restore regs pushed by VM_Fault entry +; + POP_ESI + POP_EBX + POP_EBP ; ALL regs except SEGMENT and SP are + ; restored. + add sp,4+VMTF_ES ; skip error code and GP fault stack + ; up to ES + + pop es ; reset ES for return + add sp,6 ; skip high word of ES segment + ; and DS dword + + POP_FS ; reset FS for return + add sp,2 ; skip high word of segment + + POP_GS ; reset GS for return +; +; now set flags, DS, stack, and jump to return. +; + test [RR_Flags],FLAGS_IF ;Q: IF bit set in return flags ? + jz RR_CLIexit ; N: then just return + push [RR_Flags] ; Y: enable interrupts on return + popf ; set flags + push [RR_DS] + pop ds ; set DS for exit + push ax + mov al,ENABLE_NMI + out RTC_CMD,al ; enable NMIs + pop ax + ;*** there is a small window here + ; --- NMI could occur with invalid + ; STACK + + mov ss,CS:[RR_SS] ; restore SS + mov sp,CS:[RR_SP] ; restore SP + sti ; enable ints + jmp CS:[RR_Jump] ; and return + +RR_CLIexit: + push [RR_Flags] ; leave interrupts disabled on return + popf ; set flags + push [RR_DS] + pop ds ; set DS for exit + push ax + mov al,ENABLE_NMI + out RTC_CMD,al ; enable NMIs + pop ax + ;*** there is a small window here + ; --- NMI could occur with invalid + ; STACK + + mov ss,CS:[RR_SS] ; restore SS + mov sp,CS:[RR_SP] ; restore SP + jmp CS:[RR_Jump] ; far jump for return +; +R_CODE ends ; end of segment +; + end ; end of module diff --git a/v4.0/src/MEMM/MEMM/SHIPHI.ASM b/v4.0/src/MEMM/MEMM/SHIPHI.ASM new file mode 100644 index 0000000..be09a96 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/SHIPHI.ASM @@ -0,0 +1,325 @@ + + + page 58,132 +;****************************************************************************** + TITLE SHIPHI - MODULE to ship a segment up hi +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: SHIPHI - Ship a segment up hi into extended memory +; +; Version: 0.01 +; +; Date: Sep 1, 1988 +; +; Author: ISP +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +;****************************************************************************** +; Functional Description: +; +; We need to ship data structures up hi. +; This file has routines to specify size requirements for this operation +; and to shift a segment up hi. Remember that in shipping a segment up hi +; the GDT segment should be the last to be sent up since it is modified while +; shipping a segment up hi +; +;****************************************************************************** +.lfcond +.386p + + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** + public set_src_selector ; Routines and data(GDT) for move block + public set_dest_selector + public moveb + public memreq + + public gdt_mb + + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + +;****************************************************************************** +; INCLUDE FILES +;****************************************************************************** + include vdmseg.inc ; segment definitions + include desc.inc ; + include page.inc + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +; +LAST SEGMENT + extrn get_buffer:near +LAST ENDS + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +;************************************************************************* +; +; DATA +; +;************************************************************************* + +_DATA SEGMENT + ASSUME CS:DGROUP,DS:DGROUP +; +_DATA ENDS + + + + +LAST SEGMENT +ASSUME CS:LAST,DS:DGROUP,ES:DGROUP + +; GDT for ROM Move Block calls +; +gdt_mb label word +; +gdt0_mb: GDT_ENTRY 0,0,1,0 ; Dummy seg descriptor +gdt1_mb: GDT_ENTRY 0,0,1,0 ; GDT seg descriptor +gdt2_mb: GDT_ENTRY 0,0,0,D_DATA3 ; Src seg descriptor +gdt3_mb: GDT_ENTRY 0,0,0,D_DATA3 ; Dest seg descriptor +gdt4_mb: GDT_ENTRY 0,0,1,0 ; Bios cs seg descriptor +gdt5_mb: GDT_ENTRY 0,0,1,0 ; Bios ss seg descriptor +; + +LAST ENDS + +;************************************************************************* +; +; CODE +; +;************************************************************************* +LAST SEGMENT +ASSUME CS:LAST,DS:DGROUP,ES:DGROUP + +;****************************************************************************** +; SHIPHI - routine to ship a segment up hi ; +; ; +; INPUTS: es = segment to be moved up ; +; cx = number of bytes in the segment ; +; ; +; OUTPUTS: dx:ax = new address of the segment ; +; Z set if succeeded, NZ if error ; +; ; +; USES: ax,dx,flags ; +; ; +; CALLS: ; +; ; +; AUTHOR: ISP (ISP) Sep 2, 1988 ; +; ; +;*****************************************************************************; +SHIPHI proc near + ; + push di + ; + ; first get some memory to play with + ; + call get_buffer + ; + ; then move the segment up to this new segment + ; + xor dh,dh ; dx:ax 32 bit addr of dest + xor di,di ; es:di is source segment + call moveb + ; + pop di + ; + ret +SHIPHI endp + + + +;*****************************************************************************; +;*** MOVEB *** ; +; ; +; Move data between from conventional memory to extended memory ; +; ; +; ; +; INPUTS: dl:ax = 24 bit address of extended memory address ; +; es:di = source address in lo memory +; cx = number of bytes to transfer +; ; +; OUTPUTS: Z set if succeeded ; +; NZ if error ; +; ; +; USES: ; +; ; +; AUTHOR: ISP, Sep 2,1988. ; +; ; +;*****************************************************************************; + + +MOVEB proc near + push es + push dx + push ax + push di + push cx + + + ; + ; no setup needed for dest selector, already set up. + ; + call set_dest_selector ; destination is unlock address + ; + ; for source selector we need to convert segment:offset to dl:ax + ; cx is already # of words + ; + xor dx,dx + mov ax,es + mov bx,16 + mul bx + add ax,di + adc dx,0 + + call set_src_selector ; set source segment selector to buffer + ; + ; do the block move + ; + mov si,seg LAST + mov es,si + mov si,offset LAST:gdt_mb ; ES:SI -> global descriptor table + ; + ; convert count to number of words + ; + inc cx + shr cx,1 +; + ; + mov ah,87h ; int 15 block move function code + int 15h ; unlock rom + or ah,ah ; Q: error? + ; Y: return NZ + pop cx + pop di + pop ax + pop dx + pop es + ; N: return Z + ret +MOVEB endp + + page +;****************************************************************************** +; +; set_src_selector +; Set base address, limit of source segment selector +; in gdt_mb for int 15h block move +; +; +; entry: dl:ax == source address (24 bits) +; cx == size, in words +; +; exit: gdt_mb(2) contains source base address, limit +; +; used: none +; +;****************************************************************************** +; +set_src_selector proc near +; + push di + mov di,offset LAST:gdt2_mb ; cs:di -> source seg descriptor +set_entry: + mov cs:[di.BASE_LOW],ax ; Store base address bits 15:00 + mov cs:[di.BASE_HIGH],dl ; Store base address bits 23:16 + mov cs:[di.LIMIT],cx ; Store size + sub cs:[di.LIMIT],1 ; subtract 1 => convert to limit +; + pop di + ret ; *** Return *** +; +set_src_selector endp ; End of procedure +; + page +;****************************************************************************** +; +; set_dest_selector +; Set base address, limit of destination segment selector +; in gdt_mb for int 15h block move +; +; entry: dx:ax == address (32 bits) +; cx == size of segment, in words +; ds = DGROUP +; +; exit: gdt_mb(3) contains destination base address, +; limit +; +; used: none +; +;****************************************************************************** +; +set_dest_selector proc near +; + push di + mov di,offset LAST:gdt3_mb ; cs:di -> source seg descriptor + mov cs:[di.BASE_XHI],dh ; bits 24-31 + jmp set_entry ; set this entry in gdt_mb +; + ret ; *** Return *** +; +set_dest_selector endp ; End of procedure + + + + + + + +;****************************************************************************** +; MEMREQ - routine to determine memory requirements for shifting the driver ; +; up into extended memory ; +; ; +; INPUTS: none ; +; ; +; OUTPUTS: CX = size requirements in K ; +; ; +; USES: CX, flags ; +; ; +; AUTHOR: ISP (ISP) Sep 2, 1988 ; +; ; +;*****************************************************************************; +MEMREQ proc near +; + push ax +; + mov ax,seg LAST ; this is the last segment and + ; one which is discarded. + sub ax,seg PAGESEG ; this is the first segment of the + ; region which is to be moved. + + add ax, (P_SIZE/16 -1) ; to round it up to next page bdry + shr ax, 6 ; find the size in K + add ax,16 ; throw in 4 more pages for safety + mov cx,ax ; and return the size needed +; + pop ax + ret +MEMREQ endp + +LAST ENDS + + end diff --git a/v4.0/src/MEMM/MEMM/TABDEF.ASM b/v4.0/src/MEMM/MEMM/TABDEF.ASM new file mode 100644 index 0000000..c70406e --- /dev/null +++ b/v4.0/src/MEMM/MEMM/TABDEF.ASM @@ -0,0 +1,357 @@ + + +page 58,132 +;****************************************************************************** + title TABDEF.ASM - 386 Protected Mode CPU Tables +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: TABDEF.ASM - 386 Protected Mode CPU Tables +; +; Version: 0.04 +; +; Date: January 31, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/31/86 Tables for Standalone protected mode system +; A- Modified for Virtual DOS +; 05/12/86 B- Cleanup and segment reorganization +; 06/28/86 0.02 Name changed from MEMM386 to MEMM +; 07/05/86 0.04 Moved KBD and PRINT to DCODE segment +; 07/20/88 Remove debugger codes (pc) +; +;****************************************************************************** +; +; Functional Description: +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + +NAME tabdef +; + +.xlist + include VDMseg.inc + include VDMsel.inc + include desc.inc + include page.inc +.list + + +_TEXT SEGMENT + extrn vm_trap00:far + extrn vm_trap01:far + extrn vm_trap02:far + extrn vm_trap03:far + extrn vm_trap04:far + extrn vm_trap05:far + extrn vm_trap06:far + extrn vm_trap07:far + extrn vm_trap08:far + extrn vm_trap09:far + extrn vm_trap0a:far + extrn vm_trap0b:far + extrn vm_trap0c:far + extrn vm_trap0d:far + extrn vm_trap0e:far + extrn vm_trap0f:far + extrn vm_trap50:far + extrn vm_trap51:far + extrn vm_trap52:far + extrn vm_trap53:far + extrn vm_trap54:far + extrn vm_trap55:far + extrn vm_trap56:far + extrn vm_trap57:far + extrn vm_trap70:far + extrn vm_trap71:far + extrn vm_trap72:far + extrn vm_trap73:far + extrn vm_trap74:far + extrn vm_trap75:far + extrn vm_trap76:far + extrn vm_trap77:far + + extrn EMM_pEntry:far + +_TEXT ENDS + + +;*** GDT - Global Descriptor Table +; +; This is the system GDT. Some parts are statically initialised, +; others must be set up at run time, either because masm can't +; calculate the data or it changes while the system is running. +; +; WARNING +; +; Don't change this without consulting "sel.inc", and the +; routines which initialise the gdt. +; + +GDT SEGMENT + +gdtstart label byte ; label for everyone to refer to the GDT + +GDT_ENTRY 0, 0, 1, 0 ; null selector +GDT_ENTRY 0, 0, 0, D_DATA0 ; GDT alias +GDT_ENTRY 0, 0, 0, D_DATA0 ; IDT alias +GDT_ENTRY 0, 0, 0, D_LDT0 ; LDT +GDT_ENTRY 0, 0, 0, D_DATA0 ; LDT alias +GDT_ENTRY 0, 0, 0, D_386TSS0 ; TSS +GDT_ENTRY 0, 0, 0, D_DATA0 ; TSS alias +GDT_ENTRY 0, 0, <400h>, D_DATA3 ; Real Mode IDT +GDT_ENTRY 400h, 0, <300h>, D_DATA0 ; ROM Data +GDT_ENTRY 0, 0, 0, D_CODE0 ; VDM Code +GDT_ENTRY 0, 0, 0, D_DATA0 ; VDM Data +GDT_ENTRY 0, 0, 0, D_DATA0 ; VDM Stack +GDT_ENTRY 0, 0bh, 1000h, D_DATA0 ; Mono Display +GDT_ENTRY 8000h, 0bh, 4000h, D_DATA0 ; Colour Disp +GDT_ENTRY 0, 0ah, 0, D_DATA0 ; EGA Low +GDT_ENTRY 0, 0ch, 0, D_DATA0 ; EGA High +GDT_ENTRY 800h, 0, 66h, D_DATA0 ; LOADALL +GDT_ENTRY 0, 0, 0, 0 ; debugger work 1 +GDT_ENTRY 0, 0, 0, 0 ; debugger work 2 +GDT_ENTRY 0, 0, 0, 0 ; debugger work 3 +GDT_ENTRY 0, 0, 0, 0 ; debugger work 4 +GDT_ENTRY 0, 0, 0, 0 ; debugger work 5 +GDT_ENTRY 0, 0, 0, 0 ; debugger work (Addresses all memory) +GDT_ENTRY 0, 0, 0, 0 ; general work +GDT_ENTRY 0, 0, 0, 0 ; general work +GDT_ENTRY 0, 0, 0, D_CODE0 ; maps CODE segment +GDT_ENTRY 0, 0, 0, D_DATA0 ; VM1_GSEL - vm trap scratch +GDT_ENTRY 0, 0, 0, D_DATA0 ; VM2_GSEL - vm trap scratch +GDT_ENTRY 0, 0, 0, D_DATA0 ; MBSRC_GSEL - move blk scratch +GDT_ENTRY 0, 0, 0, D_DATA0 ; MBTAR_GSEL - move blk scratch +GDT_ENTRY 0, 0, 0, D_DATA0 ; PAGET_GSEL - page table area +GDT_ENTRY 0, 0, 0, D_DATA0 ; VDM Code - Data Alias +GDT_ENTRY 0, 0, 0, D_DATA0 ; EMM1 - EMM scratch selector +GDT_ENTRY 0, 0, 0, D_DATA0 ; EMM2 - EMM scratch selector +GDT_ENTRY 0, 0, 0, D_DATA0 ; OEM0 entry +GDT_ENTRY 0, 0, 0, D_DATA0 ; OEM1 entry +GDT_ENTRY 0, 0, 0, D_DATA0 ; OEM2 entry +GDT_ENTRY 0, 0, 0, D_DATA0 ; OEM3 entry +GDT_ENTRY 0, 0, 0, D_DATA0 ; USER1 entry + + public GDTLEN +GDTLEN equ $ - gdtstart + +GDT ENDS + + +;*** TSS for protected Mode +; +; This is the VDM TSS. We only use one, for loading +; SS:SP on privilige transitions. We don't use all +; the 286 task switching stuff. +; +; + +TSS segment +; + TssArea TSS386STRUC <> +; +; I/O Bit Map for Virtual Mode I/O trapping +; + public IOBitMap +IOBitMap label byte + db 2000h dup (0) ; initialize all ports to NO trapping + db 0FFh ; last byte is all 1's + + public TSSLEN +TSSLEN equ $ - tss + +TSS ends + +;*** IDT for protected mode +; +; This is the protected mode interrupt descriptor table. +; +; The first 78h entries are defined. Only processor exceptions and +; hardware interrupts are fielded through the PM IDT. Since the +; gate DPLs are < 3, all software INTs are funneled through INT 13 +; (GP exception) and emulated. Note that Null IDT entries and limit +; exceptions produce the same results (GP error code) as DPL faults, +; so we can use a truncated IDT. This assumes no one is reprogramming +; the 8259s base vector for some reason - don't know of any DOS apps +; that do this. +; +IDT SEGMENT + +idtstart label byte + +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 00 Divide Error +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 01 Debug +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 02 NMI/287 Error +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 03 Breakpoint +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 04 INTO +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 05 BOUND/Print Screen +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 06 Invalid Opcode +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 07 287 Not Available + +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 08 Double Exception/Timer +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 09 (not on 386)/Keyboard +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 0A Invalid TSS/Cascade +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 0B Segment Not Present/COM2 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 0C Stack Fault/COM1 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 0D General Protection/LPT2 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 0E Page Fault/Diskette +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 0F Intel Reserved/LPT1 + +IDT_ENTRY 0, 0, 0 ; 10 [287 Error]/Video INT (This exception + ; cannot occur on AT architecture) +IDT_ENTRY 0, 0, 0 ; 11 Equipment Check +IDT_ENTRY 0, 0, 0 ; 12 Memory Size +IDT_ENTRY 0, 0, 0 ; 13 Disk INT +IDT_ENTRY 0, 0, 0 ; 14 RS232 +IDT_ENTRY 0, 0, 0 ; 15 Post&Wait, mov_blk via GP fault +IDT_ENTRY 0, 0, 0 ; 16 Keyboard +IDT_ENTRY 0, 0, 0 ; 17 Printer + +IDT_ENTRY 0, 0, 0 ; 18 Resident BASIC +IDT_ENTRY 0, 0, 0 ; 19 Bootstrap +IDT_ENTRY 0, 0, 0 ; 1A Time of Day +IDT_ENTRY 0, 0, 0 ; 1B Break +IDT_ENTRY 0, 0, 0 ; 1C Timer Tick +IDT_ENTRY 0, 0, 0 ; 1D Ptr to Video Param +IDT_ENTRY 0, 0, 0 ; 1E Ptr to Disk Params +IDT_ENTRY 0, 0, 0 ; 1F Ptr to Graphics + +IDT_ENTRY 0, 0, 0 ; 20 DOS +IDT_ENTRY 0, 0, 0 ; 21 DOS +IDT_ENTRY 0, 0, 0 ; 22 DOS +IDT_ENTRY 0, 0, 0 ; 23 DOS +IDT_ENTRY 0, 0, 0 ; 24 DOS +IDT_ENTRY 0, 0, 0 ; 25 DOS +IDT_ENTRY 0, 0, 0 ; 26 DOS +IDT_ENTRY 0, 0, 0 ; 27 DOS + +IDT_ENTRY 0, 0, 0 ; 28 DOS +IDT_ENTRY 0, 0, 0 ; 29 DOS +IDT_ENTRY 0, 0, 0 ; 2A DOS +IDT_ENTRY 0, 0, 0 ; 2B DOS +IDT_ENTRY 0, 0, 0 ; 2C DOS +IDT_ENTRY 0, 0, 0 ; 2D DOS +IDT_ENTRY 0, 0, 0 ; 2E DOS +IDT_ENTRY 0, 0, 0 ; 2F DOS + +IDT_ENTRY 0, 0, 0 ; 30 DOS +IDT_ENTRY 0, 0, 0 ; 31 DOS +IDT_ENTRY 0, 0, 0 ; 32 DOS +IDT_ENTRY 0, 0, 0 ; 33 DOS +IDT_ENTRY 0, 0, 0 ; 34 DOS +IDT_ENTRY 0, 0, 0 ; 35 DOS +IDT_ENTRY 0, 0, 0 ; 36 DOS +IDT_ENTRY 0, 0, 0 ; 37 DOS + +IDT_ENTRY 0, 0, 0 ; 38 DOS +IDT_ENTRY 0, 0, 0 ; 39 DOS +IDT_ENTRY 0, 0, 0 ; 3A DOS +IDT_ENTRY 0, 0, 0 ; 3B DOS +IDT_ENTRY 0, 0, 0 ; 3C DOS +IDT_ENTRY 0, 0, 0 ; 3D DOS +IDT_ENTRY 0, 0, 0 ; 3E DOS +IDT_ENTRY 0, 0, 0 ; 3F DOS + +IDT_ENTRY 0, 0, 0 ; 40 Reserved +IDT_ENTRY 0, 0, 0 ; 41 Reserved +IDT_ENTRY 0, 0, 0 ; 42 Reserved +IDT_ENTRY 0, 0, 0 ; 43 Reserved +IDT_ENTRY 0, 0, 0 ; 44 Reserved +IDT_ENTRY 0, 0, 0 ; 45 Reserved +IDT_ENTRY 0, 0, 0 ; 46 Reserved +IDT_ENTRY 0, 0, 0 ; 47 Reserved + +IDT_ENTRY 0, 0, 0 ; 48 Reserved +IDT_ENTRY 0, 0, 0 ; 49 Reserved +IDT_ENTRY 0, 0, 0 ; 4A Reserved +IDT_ENTRY 0, 0, 0 ; 4B Reserved +IDT_ENTRY 0, 0, 0 ; 4C Reserved +IDT_ENTRY 0, 0, 0 ; 4D Reserved +IDT_ENTRY 0, 0, 0 ; 4E Reserved +IDT_ENTRY 0, 0, 0 ; 4F Reserved + +; +; The following table entries assume the master 8259 base vector has been +; set up to 50h. +; +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 50 Timer Interrupt +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 51 Keyboard Interrupt +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 52 Misc peripheral Interrupt +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 53 COM2 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 54 COM1 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 55 2nd Parallel +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 56 Diskette Interrupt +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 57 1st Parallel + +IDT_ENTRY 0, 0, 0 ; 58 Reserved +IDT_ENTRY 0, 0, 0 ; 59 Reserved +IDT_ENTRY 0, 0, 0 ; 5A Reserved +IDT_ENTRY 0, 0, 0 ; 5B Reserved +IDT_ENTRY 0, 0, 0 ; 5C Reserved +IDT_ENTRY 0, 0, 0 ; 5D Reserved +IDT_ENTRY 0, 0, 0 ; 5E Reserved +IDT_ENTRY 0, 0, 0 ; 5F Reserved + +IDT_ENTRY 0, 0, 0 ; 60 User Programs +IDT_ENTRY 0, 0, 0 ; 61 User Programs +IDT_ENTRY 0, 0, 0 ; 62 User Programs +IDT_ENTRY 0, 0, 0 ; 63 User Programs +IDT_ENTRY 0, 0, 0 ; 64 User Programs +IDT_ENTRY 0, 0, 0 ; 65 User Programs +IDT_ENTRY 0, 0, 0 ; 66 User Programs +;;;IDT_ENTRY 0, 0, 0 ; 67 User Programs +IDT_ENTRY VDMC_GSEL,,D_386INT3 ; 67 ELIM + +IDT_ENTRY 0, 0, 0 ; 68 Not Used +IDT_ENTRY 0, 0, 0 ; 69 Not Used +IDT_ENTRY 0, 0, 0 ; 6A Not Used +IDT_ENTRY 0, 0, 0 ; 6B Not Used +IDT_ENTRY 0, 0, 0 ; 6C Not Used +IDT_ENTRY 0, 0, 0 ; 6D Not Used +IDT_ENTRY 0, 0, 0 ; 6E Not Used +IDT_ENTRY 0, 0, 0 ; 6F Not Used + +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 70 IRQ8 - Real Time Clock +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 71 IRQ9 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 72 IRQ10 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 73 IRQ11 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 74 IRQ12 +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 75 IRQ13 - 287 error +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 76 IRQ14 - Fixed disk +IDT_ENTRY VDMC_GSEL,,D_386INT0 ; 77 IRQ15 + + public IDTLEN +idtlen equ this byte - idtstart + +IDT ends + +PAGESEG SEGMENT +;*** Page Tables Area +; +; This area is used for the page directory and page tables +; + + public P_TABLE_CNT +P_TABLE_CNT equ 5 ; # of page tables + + public Page_Area +Page_Area label byte + db (2+P_TABLE_CNT) * P_SIZE dup (0) ; enough for page dir & + ; tables after page + ; alignment. +PAGESEG ENDS + + END + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/TRAPDEF.ASM b/v4.0/src/MEMM/MEMM/TRAPDEF.ASM new file mode 100644 index 0000000..b82f661 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/TRAPDEF.ASM @@ -0,0 +1,469 @@ + + + page 58,132 +;****************************************************************************** + title TRAPDEF.ASM - I/O trap Dispatch table +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: TRAPDEF.ASM - I/O trap Dispatch table +; +; Version: 0.04 +; +; Date: July 1, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 08/11/86 Split from IOTrap.asm +; +; 7/26/88 Added Trap handler entries for DMA ports on Channel 4 +; - Jaywant H Bharadwaj +; +;****************************************************************************** +; +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public IOTrap_Tab ; dispatches I/O trap handlers + public IOT_BadT ; Unknown port trap routine + public IOT_OEM ; OEM specific port emulation + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +; % - how many of these are actually needed? +; % - Need any includes from Win/386 DMA code - trapdef.asm ? + + include VDMseg.inc + include VDMsel.inc + include desc.inc + include elim.inc + include page.inc + include oemdep.inc + include instr386.inc + include vm386.inc +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; + +_DATA segment +;extrn _map_size:byte ; # of mapping registers used +;extrn LIMP_Addr:word +_DATA ends + +_TEXT segment +; +extrn RRP_Handler:near +extrn A20_Handler:near ; Kybd Data port - A20 watch +extrn DMABase0:near ; DMA base register for Channel 0 +extrn DMABase1:near ; DMA base register for Channel 1 +extrn DMABase2:near ; DMA base register for Channel 2 +extrn DMABase3:near ; DMA base register for Channel 3 +extrn DMABase5:near ; DMA base register for Channel 5 +extrn DMABase6:near ; DMA base register for Channel 6 +extrn DMABase7:near ; DMA base register for Channel 7 +extrn DMACnt0:near ; DMA count register for Channel 0 +extrn DMACnt1:near ; DMA count register for Channel 1 +extrn DMACnt2:near ; DMA count register for Channel 2 +extrn DMACnt3:near ; DMA count register for Channel 3 +extrn DMACnt5:near ; DMA count register for Channel 5 +extrn DMACnt6:near ; DMA count register for Channel 6 +extrn DMACnt7:near ; DMA count register for Channel 7 +extrn DMAPg0:near ; DMA page register for Channel 0 +extrn DMAPg1:near ; DMA page register for Channel 1 +extrn DMAPg2:near ; DMA page register for Channel 2 +extrn DMAPg3:near ; DMA page register for Channel 3 +extrn DMAPg5:near ; DMA page register for Channel 5 +extrn DMAPg6:near ; DMA page register for Channel 6 +extrn DMAPg7:near ; DMA page register for Channel 7 +extrn DMAClrFF1:near ; clear flip-flop cmd for channels 0-3 +extrn DMAClrFF2:near ; clear flip-flop cmd for channels 5-7 +extrn DMAMode1:near ; Mode register for channels 0-3 +extrn DMAMode2:near ; Mode register for channels 4-7 + +_TEXT ends + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** + +; +;------------------------------------------------------------------------------ +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP +; +; IOTrapTab +; One entry per port in the I/O space from 00h to FFh. +; Note that ports not specifically mapped otherwise(by IOT_OEM or +; LIM emulation and whose least significant 10 bits are less than +; 100h are also dispatched through this table(upper 6 bits assumed to +; be intended as zero since some earlier systems only had 10 bits of +; I/O addressing). +; +IOTrap_Tab label word + dw offset _TEXT:DMAbase0 ; 0 DMA base register for Channel 0 + dw offset _TEXT:DMACnt0 ; 1 DMA count register for Channel 0 + dw offset _TEXT:DMABase1 ; 2 DMA base register for Channel 1 + dw offset _TEXT:DMACnt1 ; 3 DMA count register for Channel 1 + dw offset _TEXT:DMABase2 ; 4 DMA base register for Channel 2 + dw offset _TEXT:DMACnt2 ; 5 DMA count register for Channel 2 + dw offset _TEXT:DMABase3 ; 6 DMA base register for Channel 3 + dw offset _TEXT:DMACnt3 ; 7 DMA count register for Channel 3 + dw offset _TEXT:IOT_BadT ; 8 + dw offset _TEXT:IOT_BadT ; 9 + dw offset _TEXT:IOT_BadT ; a + dw offset _TEXT:DMAMode1 ; b DMA Mode Register for for Ch 0-3 + dw offset _TEXT:DMAClrFF1 ; c clear flip-flop cmd for channels 0-3 + dw offset _TEXT:IOT_BadT ; d + dw offset _TEXT:IOT_BadT ; e + dw offset _TEXT:IOT_BadT ; f + dw offset _TEXT:IOT_BadT ; 10 + dw offset _TEXT:IOT_BadT ; 11 + dw offset _TEXT:IOT_BadT ; 12 + dw offset _TEXT:IOT_BadT ; 13 + dw offset _TEXT:IOT_BadT ; 14 + dw offset _TEXT:IOT_BadT ; 15 + dw offset _TEXT:IOT_BadT ; 16 + dw offset _TEXT:IOT_BadT ; 17 + dw offset _TEXT:IOT_BadT ; 18 + dw offset _TEXT:IOT_BadT ; 19 + dw offset _TEXT:IOT_BadT ; 1a + dw offset _TEXT:IOT_BadT ; 1b + dw offset _TEXT:IOT_BadT ; 1c + dw offset _TEXT:IOT_BadT ; 1d + dw offset _TEXT:IOT_BadT ; 1e + dw offset _TEXT:IOT_BadT ; 1f + dw offset _TEXT:IOT_BadT ; 20 + dw offset _TEXT:IOT_BadT ; 21 + dw offset _TEXT:IOT_BadT ; 22 + dw offset _TEXT:IOT_BadT ; 23 + dw offset _TEXT:IOT_BadT ; 24 + dw offset _TEXT:IOT_BadT ; 25 + dw offset _TEXT:IOT_BadT ; 26 + dw offset _TEXT:IOT_BadT ; 27 + dw offset _TEXT:IOT_BadT ; 28 + dw offset _TEXT:IOT_BadT ; 29 + dw offset _TEXT:IOT_BadT ; 2a + dw offset _TEXT:IOT_BadT ; 2b + dw offset _TEXT:IOT_BadT ; 2c + dw offset _TEXT:IOT_BadT ; 2d + dw offset _TEXT:IOT_BadT ; 2e + dw offset _TEXT:IOT_BadT ; 2f + dw offset _TEXT:IOT_BadT ; 30 + dw offset _TEXT:IOT_BadT ; 31 + dw offset _TEXT:IOT_BadT ; 32 + dw offset _TEXT:IOT_BadT ; 33 + dw offset _TEXT:IOT_BadT ; 34 + dw offset _TEXT:IOT_BadT ; 35 + dw offset _TEXT:IOT_BadT ; 36 + dw offset _TEXT:IOT_BadT ; 37 + dw offset _TEXT:IOT_BadT ; 38 + dw offset _TEXT:IOT_BadT ; 39 + dw offset _TEXT:IOT_BadT ; 3a + dw offset _TEXT:IOT_BadT ; 3b + dw offset _TEXT:IOT_BadT ; 3c + dw offset _TEXT:IOT_BadT ; 3d + dw offset _TEXT:IOT_BadT ; 3e + dw offset _TEXT:IOT_BadT ; 3f + dw offset _TEXT:IOT_BadT ; 40 + dw offset _TEXT:IOT_BadT ; 41 + dw offset _TEXT:IOT_BadT ; 42 + dw offset _TEXT:IOT_BadT ; 43 + dw offset _TEXT:IOT_BadT ; 44 + dw offset _TEXT:IOT_BadT ; 45 + dw offset _TEXT:IOT_BadT ; 46 + dw offset _TEXT:IOT_BadT ; 47 + dw offset _TEXT:IOT_BadT ; 48 + dw offset _TEXT:IOT_BadT ; 49 + dw offset _TEXT:IOT_BadT ; 4a + dw offset _TEXT:IOT_BadT ; 4b + dw offset _TEXT:IOT_BadT ; 4c + dw offset _TEXT:IOT_BadT ; 4d + dw offset _TEXT:IOT_BadT ; 4e + dw offset _TEXT:IOT_BadT ; 4f + dw offset _TEXT:IOT_BadT ; 50 + dw offset _TEXT:IOT_BadT ; 51 + dw offset _TEXT:IOT_BadT ; 52 + dw offset _TEXT:IOT_BadT ; 53 + dw offset _TEXT:IOT_BadT ; 54 + dw offset _TEXT:IOT_BadT ; 55 + dw offset _TEXT:IOT_BadT ; 56 + dw offset _TEXT:IOT_BadT ; 57 + dw offset _TEXT:IOT_BadT ; 58 + dw offset _TEXT:IOT_BadT ; 59 + dw offset _TEXT:IOT_BadT ; 5a + dw offset _TEXT:IOT_BadT ; 5b + dw offset _TEXT:IOT_BadT ; 5c + dw offset _TEXT:IOT_BadT ; 5d + dw offset _TEXT:IOT_BadT ; 5e + dw offset _TEXT:IOT_BadT ; 5f + dw offset _TEXT:A20_Handler ; A20 watch on kybd data port + dw offset _TEXT:IOT_BadT ; 61 + dw offset _TEXT:IOT_BadT ; 62 + dw offset _TEXT:IOT_BadT ; 63 + dw offset _TEXT:A20_Handler ; A20 watch on kybd cmd port + dw offset _TEXT:IOT_BadT ; 65 + dw offset _TEXT:IOT_BadT ; 66 + dw offset _TEXT:IOT_BadT ; 67 + dw offset _TEXT:IOT_BadT ; 68 + dw offset _TEXT:IOT_BadT ; 69 + dw offset _TEXT:IOT_BadT ; 6a + dw offset _TEXT:IOT_BadT ; 6b + dw offset _TEXT:IOT_BadT ; 6c + dw offset _TEXT:IOT_BadT ; 6d + dw offset _TEXT:IOT_BadT ; 6e + dw offset _TEXT:IOT_BadT ; 6f + dw offset _TEXT:IOT_BadT ; 70 + dw offset _TEXT:IOT_BadT ; 71 + dw offset _TEXT:IOT_BadT ; 72 + dw offset _TEXT:IOT_BadT ; 73 + dw offset _TEXT:IOT_BadT ; 74 + dw offset _TEXT:IOT_BadT ; 75 + dw offset _TEXT:IOT_BadT ; 76 + dw offset _TEXT:IOT_BadT ; 77 + dw offset _TEXT:IOT_BadT ; 78 + dw offset _TEXT:IOT_BadT ; 79 + dw offset _TEXT:IOT_BadT ; 7a + dw offset _TEXT:IOT_BadT ; 7b + dw offset _TEXT:IOT_BadT ; 7c + dw offset _TEXT:IOT_BadT ; 7d + dw offset _TEXT:IOT_BadT ; 7e + dw offset _TEXT:IOT_BadT ; 7f + dw offset _TEXT:IOT_BadT ; 80 + dw offset _TEXT:DMAPg2 ; 81 DMA page register for Channel 2 + dw offset _TEXT:DMAPg3 ; 82 DMA page register for Channel 3 + dw offset _TEXT:DMAPg1 ; 83 DMA page register for Channel 1 + dw offset _TEXT:RRP_Handler ; return to real port + dw offset _TEXT:RRP_Handler ; return to real port + dw offset _TEXT:IOT_BadT ; 86 + dw offset _TEXT:DMAPg0 ; 87 DMA page register for Channel 0 + dw offset _TEXT:IOT_BadT ; 88 + dw offset _TEXT:DMAPg6 ; 89 DMA page register for Channel 6 + dw offset _TEXT:DMAPg7 ; 8a DMA page register for Channel 7 + dw offset _TEXT:DMAPg5 ; 8b DMA page register for Channel 5 + dw offset _TEXT:IOT_BadT ; 8c + dw offset _TEXT:IOT_BadT ; 8d + dw offset _TEXT:IOT_BadT ; 8e + dw offset _TEXT:IOT_BadT ; 8f + dw offset _TEXT:IOT_BadT ; 90 + dw offset _TEXT:DMAPg2 ; 91 DMA page register for Channel 2 + dw offset _TEXT:DMAPg3 ; 92 DMA page register for Channel 3 + dw offset _TEXT:DMAPg1 ; 93 DMA page register for Channel 1 + dw offset _TEXT:IOT_BadT ; 94 + dw offset _TEXT:IOT_BadT ; 95 + dw offset _TEXT:IOT_BadT ; 96 + dw offset _TEXT:IOT_BadT ; 97 DMA page register for Channel 0 + dw offset _TEXT:IOT_BadT ; 98 + dw offset _TEXT:DMAPg6 ; 99 DMA page register for Channel 6 + dw offset _TEXT:DMAPg7 ; 9a DMA page register for Channel 7 + dw offset _TEXT:DMAPg5 ; 9b DMA page register for Channel 5 + dw offset _TEXT:IOT_BadT ; 9c + dw offset _TEXT:IOT_BadT ; 9d + dw offset _TEXT:IOT_BadT ; 9e + dw offset _TEXT:IOT_BadT ; 9f + dw offset _TEXT:IOT_BadT ; a0 + dw offset _TEXT:IOT_BadT ; a1 + dw offset _TEXT:IOT_BadT ; a2 + dw offset _TEXT:IOT_BadT ; a3 + dw offset _TEXT:IOT_BadT ; a4 + dw offset _TEXT:IOT_BadT ; a5 + dw offset _TEXT:IOT_BadT ; a6 + dw offset _TEXT:IOT_BadT ; a7 + dw offset _TEXT:IOT_BadT ; a8 + dw offset _TEXT:IOT_BadT ; a9 + dw offset _TEXT:IOT_BadT ; aa + dw offset _TEXT:IOT_BadT ; ab + dw offset _TEXT:IOT_BadT ; ac + dw offset _TEXT:IOT_BadT ; ad + dw offset _TEXT:IOT_BadT ; ae + dw offset _TEXT:IOT_BadT ; af + dw offset _TEXT:IOT_BadT ; b0 + dw offset _TEXT:IOT_BadT ; b1 + dw offset _TEXT:IOT_BadT ; b2 + dw offset _TEXT:IOT_BadT ; b3 + dw offset _TEXT:IOT_BadT ; b4 + dw offset _TEXT:IOT_BadT ; b5 + dw offset _TEXT:IOT_BadT ; b6 + dw offset _TEXT:IOT_BadT ; b7 + dw offset _TEXT:IOT_BadT ; b8 + dw offset _TEXT:IOT_BadT ; b9 + dw offset _TEXT:IOT_BadT ; ba + dw offset _TEXT:IOT_BadT ; bb + dw offset _TEXT:IOT_BadT ; bc + dw offset _TEXT:IOT_BadT ; bd + dw offset _TEXT:IOT_BadT ; be + dw offset _TEXT:IOT_BadT ; bf + dw offset _TEXT:IOT_BadT ; c0 DMA base register for Channel 4 + dw offset _TEXT:IOT_BadT ; c1 + dw offset _TEXT:IOT_BadT ; c2 DMA count register for Channel 4 + dw offset _TEXT:IOT_BadT ; c3 + dw offset _TEXT:DMABase5 ; c4 DMA base register for Channel 5 + dw offset _TEXT:IOT_BadT ; c5 + dw offset _TEXT:DMACnt5 ; c6 DMA count register for Channel 5 + dw offset _TEXT:IOT_BadT ; c7 + dw offset _TEXT:DMABase6 ; c8 DMA base register for Channel 6 + dw offset _TEXT:IOT_BadT ; c9 + dw offset _TEXT:DMACnt6 ; ca DMA count register for Channel 6 + dw offset _TEXT:IOT_BadT ; cb + dw offset _TEXT:DMABase7 ; cc DMA base register for Channel 7 + dw offset _TEXT:IOT_BadT ; cd + dw offset _TEXT:DMACnt7 ; ce DMA count register for Channel 7 + dw offset _TEXT:IOT_BadT ; cf + dw offset _TEXT:IOT_BadT ; d0 + dw offset _TEXT:IOT_BadT ; d1 + dw offset _TEXT:IOT_BadT ; d2 + dw offset _TEXT:IOT_BadT ; d3 + dw offset _TEXT:IOT_BadT ; d4 + dw offset _TEXT:IOT_BadT ; d5 + dw offset _TEXT:DMAMode2 ; d6 DMA Mode Register for channels 4-7 + dw offset _TEXT:IOT_BadT ; d7 + dw offset _TEXT:DMAClrFF2 ; d8 clear flip-flop cmd for channels 5-7 + dw offset _TEXT:IOT_BadT ; d9 + dw offset _TEXT:IOT_BadT ; da + dw offset _TEXT:IOT_BadT ; db + dw offset _TEXT:IOT_BadT ; dc + dw offset _TEXT:IOT_BadT ; dd + dw offset _TEXT:IOT_BadT ; de + dw offset _TEXT:IOT_BadT ; df + dw offset _TEXT:IOT_BadT ; e0 + dw offset _TEXT:IOT_BadT ; e1 + dw offset _TEXT:IOT_BadT ; e2 + dw offset _TEXT:IOT_BadT ; e3 + dw offset _TEXT:IOT_BadT ; e4 + dw offset _TEXT:IOT_BadT ; e5 + dw offset _TEXT:IOT_BadT ; e6 + dw offset _TEXT:IOT_BadT ; e7 + dw offset _TEXT:IOT_BadT ; e8 + dw offset _TEXT:IOT_BadT ; e9 + dw offset _TEXT:IOT_BadT ; ea + dw offset _TEXT:IOT_BadT ; eb + dw offset _TEXT:IOT_BadT ; ec + dw offset _TEXT:IOT_BadT ; ed + dw offset _TEXT:IOT_BadT ; ee + dw offset _TEXT:IOT_BadT ; ef + dw offset _TEXT:IOT_BadT ; f0 + dw offset _TEXT:IOT_BadT ; f1 + dw offset _TEXT:IOT_BadT ; f2 + dw offset _TEXT:IOT_BadT ; f3 + dw offset _TEXT:IOT_BadT ; f4 + dw offset _TEXT:IOT_BadT ; f5 + dw offset _TEXT:IOT_BadT ; f6 + dw offset _TEXT:IOT_BadT ; f7 + dw offset _TEXT:IOT_BadT ; f8 + dw offset _TEXT:IOT_BadT ; f9 + dw offset _TEXT:IOT_BadT ; fa + dw offset _TEXT:IOT_BadT ; fb + dw offset _TEXT:IOT_BadT ; fc + dw offset _TEXT:IOT_BadT ; fd + dw offset _TEXT:IOT_BadT ; fe + dw offset _TEXT:IOT_BadT ; ff + +;****************************************************************************** +; IOT_BadT - GP fault on Unknown I/O address +; +; DESCRIPTION: This routine is entered by being in the IOTrap_Tab above +; and also for I/O ports which are not LIM(DMA) ports and are not +; emulated by IOT_OEM routine below and the first 10 bits of the +; address is greater than 100h. Note that only the first 10 bits +; of the port (times 2) is passed in BX. If the entire port +; address is desired, it is available on the stack as the value +; which is popped into DX. +; +; ENTRY: Protected Mode Ring 0 +; return address, DX, DS, return address on stack +; AL = byte to output to port. +; BX == 2 * port address(either 0-1FE or 200-7FE) +; DX == 0 => Emulate input +; <> 0 => Emulate output +; DS = DGROUP +; SS:BP = points to stack frame on entry to GP fault handler +; +; +; EXIT: Protected Mode Ring 0 +; First return address, pop'd from stack. +; DX and DS restored from stack. +; BX = DX on entry +; STC => I/O NOT emulated. +; +; WARNING:*********** +; This routine is closely allied with IOTrap which is in IOTrap. +; It is assumed that IOTrap puts the stack in a certain state! +; *********** + +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +; +IOT_BadT proc near + pop bx ; dump return address + mov bx,dx ; restore BX + pop dx ; restore DX(port address) + pop ds ; restore DS + stc ; port not emulated ! + ret ; and return +IOT_BadT endp + +;****************************************************************************** +; IOT_OEM - Handles OEM specific I/O traps +; +; ENTRY: Protected Mode Ring 0 +; AL = byte to output to port. +; DX = port address for I/O. +; SS:BP = points to stack frame on entry to GP fault handler +; BX = 0 => Emulate Input. +; <>0 => Emulate Output. +; DS = DGROUP +; stack: near return to IOTrap, DX, DS, near return from IOTrap +; +; EXIT: Protected Mode Ring 0 +; Either emulate I/O and pop return, DX, DS from stack and RET +; with CF = 1(CF = 0 if I/O is to be ignored!?!?). +; Or just return(no emulation done) +; +; +; WARNING:*********** +; This routine is closely allied with IOTrap. +; It assumes that the stack is in a certain state! +; *********** +; +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +IOT_OEM proc near +; cmp dx,???? +; jnz NoEmulation +; or bx,bx +; jnz NoEmulation +; mov al,???? ;emulate input +; pop dx ;remove return +; pop dx ;restore DX +; pop ds ;restore DS +; ret ;return from IOTRAP +; +;NoEmulation: + ret ; no emulation +IOT_OEM endp + + +_TEXT ends + + end + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/UTIL.ASM b/v4.0/src/MEMM/MEMM/UTIL.ASM new file mode 100644 index 0000000..221efdf --- /dev/null +++ b/v4.0/src/MEMM/MEMM/UTIL.ASM @@ -0,0 +1,335 @@ + + +page 58,132 +;****************************************************************************** + title UTIL - general MEMM utilities +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: UTIL - utilities +; +; Version: 0.04 +; +; Date: June 11, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/11/86 Original from i286.asm +; 06/18/86 0.01 in GoVirtual - added code to init VDM state variables +; 06/25/86 0.02 in GoVirtual - more DiagByte state variable. +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 06/29/86 0.02 Changed check code for ROM write protect state +; 07/01/86 0.03 Added call to InitDMA in GoVirtual +; 07/05/86 0.04 Moved code to InitLOCK +; 07/05/86 0.04 Added FarGoVirtual and moved IsReal to PRINT.ASM +; 07/06/86 0.04 Changed assume to DGROUP and moved stack out of DGROUP +; +;****************************************************************************** +; +; Functional Description: +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + + public GoVirtual + public FarGoVirtual + public SelToSeg + +;****************************************************************************** +; D E F I N E S +;****************************************************************************** + include VDMseg.inc + include VDMsel.inc + include desc.inc + include instr386.inc + include oemdep.inc + +FALSE equ 0 +TRUE equ not FALSE + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +_DATA SEGMENT + +extrn TEXT_Seg:word ; segment for _TEXT +extrn GDT_Seg:word ; segment for GDT +extrn TSS_Seg:word ; segment address of TSS +extrn Page_Dir:word ; 32-bit address of Page Directory Table + +extrn Active_Status:byte + +_DATA ENDS + +_TEXT SEGMENT + +extrn InitDMA:near ; (elimtrap.asm) +extrn EnableA20:near ; (modesw.asm) +extrn A20_Trap_Init:near ; (a20trap.asm) +extrn RR_Trap_Init:near ; (RRTrap.asm) +extrn OEM_Trap_Init:near ; (OEMTrap.asm) + +_TEXT ENDS + +STACK segment + extrn kstack_top:byte +STACK ends + +ifndef NOHIMEM + +R_CODE segment +extrn InitLock:far +R_CODE ends + +endif + + page +;****************************************************************************** +; S E G M E N T D E F I N I T I O N S +;****************************************************************************** + +;****************************************************************************** +; _TEXT segment +;****************************************************************************** + +_TEXT SEGMENT + assume cs:_TEXT, ds:DGROUP, es:DGROUP + +;****************************************************************************** +; FarGoVirtual - far link for GoVirtual +; +; NOTE: this is a FAR routine. +; +; ENTRY: Real Mode +; DS = DGROUP +; +; EXIT: Virtual Mode +; VDM state variables initialized +; +; USED: none +; +;****************************************************************************** +FarGoVirtual proc far + call GoVirtual + ret +FarGoVirtual endp + +;****************************************************************************** +; GoVirtual - go to virtual mode +; +; ENTRY: Real Mode +; DS = DGROUP +; +; EXIT: Virtual Mode +; VDM state variables initialized +; +; USED: none +; +;****************************************************************************** +GoVirtual proc near +; + PUSH_EAX + push bx + push bp + push ds + push es + PUSH_FS + PUSH_GS +; + cli ; interrupts OFF +; +; init VDM state variables +; + push es + mov ax,[TSS_Seg] + mov es,ax ; ES -> TSS + call A20_Trap_Init ; init a20 line watch + call RR_Trap_Init ; init return to real watch + call OEM_Trap_Init ; init any other I/O port watches + pop es + + mov [Active_Status],1 + + call InitDMA ; init DMA watcher + +ifndef NOHIMEM + call FAR PTR InitLOCK ; init status of TABLE lock +endif + +; +; mask off master 8259 to prevent all interrupts during setup +; + call MaskIntAll ; Mask all interrupts +; +; Set the CPU into 386 protected mode. +; +; The following CPU registers are changed to have values +; appropriate to protected mode operation: +; +; CS, DS, ES, SS, TR, LDT, Flags, MSW, GDT, IDT + call EnableA20 ; enable A20 address line + +; +; load CR3 register for paging +; + OP32 + mov ax,[Page_Dir] ; EAX = 32-bit address of Page Dir + + MOV_CR3_EAX + +; +; load gdt and ldt base registers +; + mov ax,[GDT_Seg] + mov ds, ax ; DS:0 = ptr to gdt + lgdt qword ptr ds:[GDTD_GSEL] + lidt qword ptr ds:[IDTD_GSEL] +; +; go protected and enable paging - turn on bits in CR0 +; + MOV_EAX_CR0 + + OP32 + or ax,MSW_PROTECT ; or EAX,imm32 - enable PE bit - PROT MODE + dw 8000h ; - enable PG bit - PAGING + + MOV_CR0_EAX + +; far jump to flush prefetch, and reload CS + + db 0eah ; far jmp opcode + dw offset _TEXT:pm1 ; offset + dw VDMC_GSEL ; selector +pm1: +; +; We are now protected, set the Task Register and LDT Register +; + mov ax,TSS_GSEL + ltr ax + + xor ax, ax ; LDT is null, not needed + lldt ax +; +; save current stack pointer for after return to VM +; + mov bx,ss ; BX = saved SS + mov bp,sp ; BP = saved SP +; +; set the stack selector to RING 0 stack +; + mov ax, VDMS_GSEL + mov ss, ax + mov sp, offset STACK:kstack_top +; +; now reload DS and ES to be data selectors for protected mode +; + mov ax, VDMD_GSEL + mov ds, ax + assume ds:DGROUP + mov es, ax + assume es:DGROUP + +; +; reset NT bit so IRET won't attempt a task switch +; + pushf + pop ax + and ax,0FFFh + push ax + popf +; +; build stack frame for IRET into virtual mode +; + push 0 + push 0 ; GS + push 0 + push 0 ; FS + push 0 + push seg DGROUP ; DS (DGROUP for variable access) + push 0 + push 0 ; ES + + push 0 + push bx ;* virtual mode SS + + push 0 + push bp ;* virtual mode ESP + + push 2 ; EFlags high, VM bit set + push 3000h ;* EFlags low, NT = 0, IOPL=3, CLI + + push 0 + mov ax, [TEXT_Seg] + push ax ; CS + push 0 + mov ax, offset _TEXT:VM_return + push ax ; IP + + OP32 ; 32 bit operand size override + iret + +; +; Enter Virtual Mode here +; +VM_return: +; +; re-enable interrupts +; + call RestIntMask ; Restore interrupt mask + POP_GS + POP_FS + pop es + pop ds + pop bp + pop bx + POP_EAX + ret +GoVirtual endp + + +;** SelToSeg - convert selector to a segment number +; +; The protected mode selector value is converted to a +; real mode segment number. +; +; ENTRY BX = selector +; EXIT AX = segment number +; USES BX, Flags, other regs preserved +; +; WARNING This code only works on a 286. It can be +; called only in protected mode. + +SelToSeg proc near + push ds + mov ax,LDTD_GSEL + test bx,TAB_LDT ; is the selector in the LDT? + jnz sts_addr ; yes, + mov ax,GDTD_GSEL ; selector is in the GDT +sts_addr: + mov ds,ax + and bl,0F8h + + mov ax,word ptr ds:[bx + 2] ; low 16 bits of base address + mov bh,ds:[bx + 4] ; high 8 bits of base address + shr ax,4 + shl bh,4 + mov bl,0 + add ax,bx ; AX = segment number for selector + pop ds + ret +SelToSeg endp + +_TEXT ends + + end diff --git a/v4.0/src/MEMM/MEMM/VDMINIT.ASM b/v4.0/src/MEMM/MEMM/VDMINIT.ASM new file mode 100644 index 0000000..a6e7072 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VDMINIT.ASM @@ -0,0 +1,527 @@ + + +page 58,132 +;****************************************************************************** + title VDM_Init - VDM initialization module +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: VDM_Init - VDM initialization routine +; +; Version: 0.05 +; +; Date: June 3,1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/03/86 Original from VDM MAIN.ASM module +; 06/16/86 0.01 Added code to dword align LL buffer +; 06/21/86 0.02 moved cld in init_pages +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/06/86 0.04 changed assume to DGROUP and moved stack out of +; DGROUP +; 07/10/86 0.05 Init of RCODEA_GSEL +; 07/10/86 0.05 Added PageT_Seg +; 07/20/88 Removed debugger codes (pc) +; +;****************************************************************************** +; +; Functional Description: +; +; This module is the general initialization module for the Virtual DOS +; Monitor part of MEMM. This module initializes the protected mode +; GDT, IDT, TSS (and I/O BitMap), and the Page Tables. This module also +; initializes all variables used by the VDM code. This module returns +; to the calling routine in Virtual Mode. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p +;****************************************************************************** +; P U B L I C S +;****************************************************************************** + + public VDM_Init + public PageD_Seg + public PageT_Seg + public Page_Dir + +;****************************************************************************** +; D E F I N E S +;****************************************************************************** + include VDMseg.inc + include VDMsel.inc + include desc.inc + include instr386.inc + include page.inc + +FALSE equ 0 +TRUE equ not FALSE +CR equ 0dh +LF equ 0ah + +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +_DATA SEGMENT +extrn P_TABLE_CNT:abs +extrn ELOff:word ; offset of LL buffer +_DATA ENDS + +_TEXT SEGMENT + +extrn InitBitMap:far ; (vminit.asm) + +_TEXT ENDS + +GDT SEGMENT +extrn GDTLEN:abs +GDT ENDS + +IDT SEGMENT +extrn IDTLEN:abs +IDT ENDS + +TSS SEGMENT +extrn TSSLEN:abs +TSS ENDS + +PAGESEG SEGMENT +extrn Page_Area:byte +PAGESEG ENDS + + +LAST SEGMENT +extrn SetSegDesc:near +extrn SegTo24:near +extrn SetPageEntry:near +extrn get_init_a20_state:near +extrn OEM_Init_Diag_Page:near +LAST ENDS + +;****************************************************************************** +; S E G M E N T D E F I N I T I O N S +;****************************************************************************** + +; +; Ring 0 stack for VDM exception/int handling +; +STACK SEGMENT +stkstrt label byte + + db STACK0_SIZE dup(0) + + public kstack_top +kstack_top label byte + + db 400h dup (0) + public exe_stack +exe_stack label byte + +STACK ENDS + +_DATA SEGMENT + +PageD_Seg dw 0 ; segment for Page Directory +PageT_Seg dw 0 ; segment for Page Tables +Page_Dir dd 0 ; 32 bit address of Page Directory + +_DATA ENDS + +; +; code +; +LAST SEGMENT + + assume cs:LAST, ds:DGROUP, es:DGROUP + +;****************************************************************************** +; VDM_Init - VDM initialization routine +; +; +; ENTRY: Real Mode +; DS = DGROUP +; GDT = GDT segment +; TSS = TSS segment +; +; EXIT: Real Mode +; VDM Tables initialized +; TSS initialized +; +; USED: none +; +;****************************************************************************** +VDM_Init proc near +; + pushf + pusha + PUSH_EAX + push ds + push es +; + push ds + pop es ; ES = data +; + cli +; + call InitGdt ;;; initialize GDT descriptors +; +; initialize Page Table, I/O Bit Map and LIM h/w emulator +; + call InitPages ;;; initialize paging tables + call InitBitMap ;;; initialize I/O Bit Map +; +; initialize TSS,GDTR,IDTR +; +; set ring 0 SS:SP in the TSS so we can take outer ring traps + + mov ax, seg TSS + mov es,ax ; ES -> TSS + xor di,di ; ES:DI -> TSS + + mov ES:[di.TSS386_SS0], VDMS_GSEL + mov word ptr ES:[di.TSS386_ESP0lo], offset STACK:kstack_top + mov word ptr ES:[di.TSS386_ESP0hi], 0 + +; now set CR3 in the TSS + + db 66h + mov ax,word ptr [Page_Dir] ; EAX = page dir 32 bit addr + db 66h + mov word ptr ES:[di.TSS386_CR3],ax ; mov EAX into CR3 spot in TSS + +; clear the TSS busy flag + + mov ax,seg GDT + mov es, ax ; DS:0 = ptr to gdt + + and byte ptr ES:[TSS_GSEL + 5], 11111101B + +; +; dword align the LL buffer (move foward) +; + mov ax,[ELOff] + and ax,0003h ; MOD 4 + mov bx,4 + sub bx,ax ; BX = amount to add to dword align + add [ELOff],bx ; dword align it... + +; +; and return +; + pop es + pop ds + POP_EAX + popa + popf + ret +VDM_Init endp + +;** InitGdt - initialise GDT +; +; Some of the GDT is statically initialised. This routine +; initialises the rest, except the LDT pointer which +; changes dynamically, and the VDM stack which changes too. +; +; ENTRY GDT:0 = GDT to use. +; EXIT None +; USES All except BP +; +; WARNING This code only works on a 286. +; Designed to be called from real mode ONLY. + + public InitGdt +InitGdt proc near + push es + + mov ax,GDT + mov es,ax ; ES:0 -> gdt + + mov ax,GDT + call SegTo24 + mov cx,GDTLEN + mov ah,D_DATA0 + mov bx,GDTD_GSEL + call SetSegDesc ; Set up GDT alias descriptor + + mov ax,IDT + call SegTo24 + mov cx,IDTLEN + mov ah,D_DATA0 + mov bx,IDTD_GSEL + call SetSegDesc ; Set up IDT alias descriptor + + mov ax,TSS + call SegTo24 + mov cx,TSSLEN + mov ah,D_386TSS0 + mov bx,TSS_GSEL + call SetSegDesc ; Set up TSS descriptor + + mov ah,D_DATA0 + mov bx,TSSD_GSEL + call SetSegDesc ; Set up TSS alias descriptor + + mov ax,seg _TEXT + call SegTo24 + mov cx,0 ; 0 = 64K size + mov ah,D_CODE0 + mov bx,VDMC_GSEL + call SetSegDesc ; Set up VDM Code descriptor + + mov ax,_TEXT + call SegTo24 + mov cx,0 ; 0 = 64K size + mov ah,D_DATA0 + mov bx,VDMCA_GSEL + call SetSegDesc ; Set up VDM Code segment alias descr + + mov ax,R_CODE + call SegTo24 + mov cx,0 ; 0 = 64K size + mov ah,D_DATA0 + mov bx,RCODEA_GSEL + call SetSegDesc ; Set up R_CODE segment alias descriptor + + mov ax,seg DGROUP + call SegTo24 + mov cx,0 ; 0 = 64K size + mov ah,D_DATA0 + mov bx,VDMD_GSEL + call SetSegDesc ; Set up VDM Data descriptor + + mov ax, seg STACK ; set up Ring 0 stack + call SegTo24 + mov cx, offset STACK:kstack_top + mov ah, D_DATA0 + mov bx, VDMS_GSEL + call SetSegDesc + + pop es + ret +InitGdt endp + +;** InitPages - initialize Page Directory and Table +; +; This routine initializes a page directory and a page table. +; Both of these are aligned on a physical page boundary by +; starting them at the nearest bndry. Thus, the page table area +; must be large enough to allow this alignment. +; +; The page dir and table set up by this routine maps the linear +; addresses for Virtual mode programs into physical addresses using +; the following scheme. +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; 00110000h - 0100FFFFh 00100000h - 00FFFFFFh (top 15Meg of phys) +; +; ISP,PC: The above was totally unnecessary. When the A20 is turned +; off the 64k at 1M is anyway unaccessible. A better mapping +; has been implemented here: +; +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; 00110000h - 01000000h 00110000h - 01000000h (top 15Meg of phys) +; 01000000h - 0100ffffh xxxx0000h - xxxxffffh (Done in OEMPROC) +; +; +; ENTRY PAGESEG:Page_Area = pointer to page table area. +; DS = DGROUP +; EXIT DS:PageD_Seg = seg ptr for page directory. +; DS:PageT_Seg = seg ptr for page tables +; DS:Page_Dir = 32 bit addr for page directory. +; USES none +; +; WARNING This code only works on a 286/386. +; Designed to be called from real mode ONLY. + + public InitPages +InitPages proc near + push ax + push bx + push cx + push dx + push di + push es + cld ; strings foward +; +; get physical pointer to nearest page +; + mov ax,offset PAGESEG:Page_Area + add ax,15 + shr ax,4 ; AX = seg offset for page area + mov bx,PAGESEG ; PAGESEG is on a 256 boundary + add ax,bx ; AX = seg offset for page area + add ax,0FFh ; 0FFh = # of paras in page - 1 + xor al,al ; AX = seg addr for page align + mov [PageD_Seg],ax ; save it +; + xor di,di + mov es,ax ; ES:DI = ptr to Page Directory +; + mov dl,ah + shr dl,4 ; DL = bits 16 - 19 + xor dh,dh ; DX = bits 16 - 31 + shl ah,4 ; AX = bits 0 - 15 + mov word ptr [Page_Dir],AX ; DX,AX = 32 bit addr of Page Directory + mov word ptr [Page_Dir+2],DX ; save it +; +; get addr of Page Table for Page Directory entry +; + add ax,1000h ; add page + adc dx,0h ; carry it => DX,AX = addr of page table +; +; set entries in page directory +; +; ES:[DI] pts to first entry in page directory +; DX,AX = addr of first page table +; + mov bh,0 + mov bl,P_AVAIL ; make table available to all + mov cx,P_TABLE_CNT ; set entries in page table directory + ; for existing page tables. +init_dir: + call SetPageEntry ; set entry for first page table +; +; ES:[DI] pts to next entry in page directory + add ax,1000h + adc dx,0 ; DX,AX = addr of next page table + loop init_dir ; set next entry in dir +; +; set rest of entries in page directory to not present + mov bh,0 + mov bl,NOT P_PRES ; mark page table as not present + mov cx,400h + sub cx,P_TABLE_CNT ; set rest of entries in directory +set_dir: + call SetPageEntry + loop set_dir +; +; set entries in page tables +; +; first 1 Meg +; Linear Addr Physical Addr +; 00000000h - 000FFFFFh 00000000h - 000FFFFFh +; + mov ax,[PageD_Seg] ; get segment for page directory + add ax,0100h ; add 1 page to get to first page table + mov [PageT_Seg],ax ; save it + + mov es,ax + xor di,di ; ES:[DI] pts to first page table + + xor dx,dx + xor ax,ax ; start with physical addr = 00000000h + mov bh,0 + mov bl,P_AVAIL ; make pages available to all + mov cx,100h ; set 1 Meg worth of entries in table +set1_tentry: + call SetPageEntry + ; ES:[DI] pts to next page table entry + add ax,1000h ; next physical page + adc dx,0h ; address in DX,AX + loop set1_tentry ;Q: done with this page table + ; N: the loop again + ; Y: set next entries in next tables +; 64k wraparound at 1.0 Meg +; Linear Addr Physical Addr +; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound) +; + call get_init_a20_state ; the physical a20 state has already + ; been established + jnz skip_wrap + xor dx,dx + xor ax,ax ; start with physical addr = 00000000h +skip_wrap: + mov bh,0 + mov bl,P_AVAIL ; make pages available to all + mov cx,10h ; set 64k worth of entries +set2_tentry: + call SetPageEntry + ; ES:[DI] pts to next page table entry + add ax,1000h ; next physical page + adc dx,0h ; address in DX,AX + loop set2_tentry ;Q: done with the wraparound entries + ; N: loop again + ; Y: all done +; +; last (15M - 64K) of linear addresses ( for Move Block/Loadall ) +; Linear Addr Physical Addr +; 00110000h - 01000000h 00110000h - 01000000h +; + mov dx,0011h + xor ax,ax ; start with 00110000h physical + mov bh,0 + mov bl,P_AVAIL ; make pages available to all + mov cx,(4*400h)-100h-10h ; (15M-64K) worth of Page Table Entries +set3_tentry: + call SetPageEntry + ; ES:[DI] pts to next page table entry + add ax,1000h ; next physical page + adc dx,0h ; address in DX,AX + loop set3_tentry ;Q: done with last entries + ; N: loop again + ; Y: all done + +; +; fill out entries in last table as not present +; + xor ax,ax + xor dx,dx ; addr = 0 + mov bh,0 + mov bl,0 ; page not present +; +; we can actually forget about this last page table because we +; are not going to use them +; + mov cx,400h ; last table +setL_tentry: + call SetPageEntry ; set this entry + loop setL_tentry +; +; our honorable OEM Compaq has to be supported, so we have this hook into +; OEMPROC to modify the last page table to point at the diagnostics segment +; + call OEM_Init_Diag_Page +; +; all done with page dir and table setup +; set up page directory and page table selectors +; + mov ax,seg GDT + mov es,ax ; ES pts to GDT + + mov ax,[PageT_Seg] ; seg for page tables + call SegTo24 + mov cx,0 ; enough room for tables + mov ah,D_DATA0 + mov bx,PAGET_GSEL + call SetSegDesc ; set up page tables entry + +; +; EXIT +; + pop es + pop di + pop dx + pop cx + pop bx + pop ax + ret +InitPages endp + +LAST ends + + END + + diff --git a/v4.0/src/MEMM/MEMM/VDMSEG.INC b/v4.0/src/MEMM/MEMM/VDMSEG.INC new file mode 100644 index 0000000..5a73bb3 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VDMSEG.INC @@ -0,0 +1,168 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: VDMSEG.INC - Segment Ordering and attributes for VDM +; +; Version: 0.04 +; +; Date: May 12, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; Original +; 05/12/86 A Cleanup and segment reorganization +; 06/03/86 C changed order and added STACK and STACK0,STACK0_SIZE +; 06/06/86 C changed CODE to _TEXT and DATA to _DATA +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/05/86 0.04 Re-organized to allow code seg move +; 06/03/88 add use16 to all segments +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +ifndef NOHIMEM +; +; SEGMENT definitions and order +; + +;* CODE area containing EMM/VDISK headers and writeable Real mode code +R_CODE SEGMENT PARA USE16 PUBLIC 'R_CODE' +R_CODE ENDS + +;* Contains initialized variables and variables used at startup. +_DATA SEGMENT WORD USE16 PUBLIC 'DATA' +_DATA ENDS + +;* read only constants for C +CONST SEGMENT WORD USE16 PUBLIC 'CONST' +CONST ENDS + +;* uninitialized static data for C +_BSS SEGMENT WORD USE16 PUBLIC 'BSS' +_BSS ENDS + +;* Ring 0 stack in VDM +STACK SEGMENT PARA USE16 STACK 'STACK' +STACK ENDS + +; +; data group +; +DGROUP GROUP _DATA,CONST,_BSS + +;* The code comprising the system. Must be READ-ONLY in real mode. +_TEXT SEGMENT BYTE USE16 PUBLIC 'CODE' +_TEXT ENDS + +;* Global Descriptor Table +GDT SEGMENT PARA USE16 COMMON +GDT ENDS + +;* Local Descriptor Table +LDT SEGMENT PARA USE16 COMMON +LDT ENDS + +;* Interrupt Descriptor Table +IDT SEGMENT PARA USE16 COMMON +IDT ENDS + +;* Task State Segment +TSS SEGMENT PARA USE16 COMMON +TSS ENDS + +;* Contains initialized variables and variables used at startup. +PAGESEG SEGMENT PARA USE16 PUBLIC 'PAGES' +PAGESEG ENDS + +;* Initialization code and variables. Used for data later. +; Must be last segment. +LAST SEGMENT PARA USE16 PUBLIC 'LAST' +LAST ENDS + + + +else +; +; SEGMENT definitions and order +; + +;* CODE area containing EMM/VDISK headers and writeable Real mode code +R_CODE SEGMENT PARA USE16 PUBLIC 'R_CODE' +R_CODE ENDS + +;* Global Descriptor Table +GDT SEGMENT PARA USE16 COMMON +GDT ENDS + +;* Local Descriptor Table +LDT SEGMENT PARA USE16 COMMON +LDT ENDS + +;* Interrupt Descriptor Table +IDT SEGMENT PARA USE16 COMMON +IDT ENDS + +;* Task State Segment +TSS SEGMENT PARA USE16 COMMON +TSS ENDS + +;* Contains initialized variables and variables used at startup. +_DATA SEGMENT WORD USE16 PUBLIC 'DATA' +_DATA ENDS + +;* read only constants for C +CONST SEGMENT WORD USE16 PUBLIC 'CONST' +CONST ENDS + +;* uninitialized static data for C +_BSS SEGMENT WORD USE16 PUBLIC 'BSS' +_BSS ENDS + +;* Ring 0 stack in VDM +STACK SEGMENT PARA USE16 STACK 'STACK' +STACK ENDS + +; +; data group +; +DGROUP GROUP _DATA,CONST,_BSS + +;* The code comprising the system. Must be READ-ONLY in real mode. +_TEXT SEGMENT BYTE USE16 PUBLIC 'CODE' +_TEXT ENDS + +;* Contains dynamically sized emm data structures. +VDATA SEGMENT WORD USE16 PUBLIC 'VDATA' +VDATA ENDS + +;* Contains initialized variables and variables used at startup. +PAGESEG SEGMENT PARA USE16 PUBLIC 'PAGES' +PAGESEG ENDS + +;* Initialization code and variables. Used for data later. +; Must be last segment. +LAST SEGMENT PARA USE16 PUBLIC 'LAST' +LAST ENDS +endif +; +; segment related equates +; + +; ring 0 stack size +STACK0_SIZE equ 512 + +.list ; end of VDMSEG.INC + diff --git a/v4.0/src/MEMM/MEMM/VDMSEL.INC b/v4.0/src/MEMM/MEMM/VDMSEL.INC new file mode 100644 index 0000000..f408c40 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VDMSEL.INC @@ -0,0 +1,101 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: VDMSEL.INC - Selector Definitions for MEMM +; +; Version: 0.05 +; +; Date: May 12, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; Original +; 05/12/86 A Cleanup and segment reorganization +; 06/07/86 C merged with module from Rick +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/10/86 0.05 Changed CODE_GSEL to RCODEA_GSEL +; 07/20/88 Remove debugger selectors +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + + +; +; DESCRIPTION +; +; These are the fixed selector numbers for the GDT and LDT +; +; All are declared with RPL = 0 so they can easily be used +; as table indices. +; +; Do not change anything without consulting files which include +; this one. Add new selectors to the end and update the +; gdt declaration and initialisation code elsewhere. +; + +; Define LDT and GDT table bits + +TAB_LDT equ 4h +TAB_GDT equ 0h + + +; Define GDT selectors + +GDTD_GSEL equ 008h OR TAB_GDT ; gdt data alias +IDTD_GSEL equ 010h OR TAB_GDT ; idt data alias +LDT_GSEL equ 018h OR TAB_GDT ; ldt +LDTD_GSEL equ 020h OR TAB_GDT ; ldt data alias +TSS_GSEL equ 028h OR TAB_GDT ; tss +TSSD_GSEL equ 030h OR TAB_GDT ; tss data alias +RM_IDT_GSEL equ 038h OR TAB_GDT ; real mode idt (locn 0) +ROMDATA_GSEL equ 040h OR TAB_GDT ; maps 40:0 - DON'T CHANGE!! +VDMC_GSEL equ 048h OR TAB_GDT ; VDM Code selector +VDMD_GSEL equ 050h OR TAB_GDT ; VDM Data Selector +VDMS_GSEL equ 058h OR TAB_GDT ; VDM stack selector +MONO_GSEL equ 060h OR TAB_GDT ; monochrome display memory +COLOUR_GSEL equ 068h OR TAB_GDT ; colour display memory +EGA1_GSEL equ 070h OR TAB_GDT ; first EGA sel +EGA2_GSEL equ 078h OR TAB_GDT ; second EGA sel +LOADALL_GSEL equ 080h OR TAB_GDT ; loadall buffer - DON'T CHANGE +;DEBC_GSEL equ 088h or TAB_GDT ; debugger work descr +;DEBD_GSEL equ 090h or TAB_GDT ; debugger work descr +;DEBW1_GSEL equ 098h or TAB_GDT ; debugger work descr +;DEBW2_GSEL equ 0A0h or TAB_GDT ; debugger work descr +DEB1_GSEL equ 088h or TAB_GDT ; deb386 word descr +DEB2_GSEL equ 090h or TAB_GDT ; deb386 word descr +DEB3_GSEL equ 098h or TAB_GDT ; deb386 word descr +DEB4_GSEL equ 0A0h or TAB_GDT ; deb386 word descr +DEB5_GSEL equ 0A8h or TAB_GDT ; deb386 word descr +DEBX_GSEL equ 0B0h or TAB_GDT ; deb386 descr for all of addressing space +K_PUTC286 equ 0B8h OR TAB_GDT ; 286 call gate to kputc +K_GETC286 equ 0C0h OR TAB_GDT ; 286 call gate to kgetc +RCODEA_GSEL equ 0C8h OR TAB_GDT ; data alias for R_CODE segment +VM1_GSEL equ 0D0h OR TAB_GDT ; scratch for vm handler +VM2_GSEL equ 0D8h OR TAB_GDT ; scratch for vm handler +MBSRC_GSEL equ 0E0h OR TAB_GDT ; source sel for move blk +MBTAR_GSEL equ 0E8h OR TAB_GDT ; target sel for move blk +PAGET_GSEL equ 0F0h OR TAB_GDT ; page table area sel +VDMCA_GSEL equ 0F8h OR TAB_GDT ; VDM code segment alias +EMM1_GSEL equ 100h OR TAB_GDT ; EMM scratch selector +EMM2_GSEL equ 108h OR TAB_GDT ; EMM scratch selector +OEM0_GSEL equ 110h OR TAB_GDT ; OEM specific selector +OEM1_GSEL equ 118h OR TAB_GDT ; OEM specific selector +OEM2_GSEL equ 120h OR TAB_GDT ; OEM specific selector +OEM3_GSEL equ 128h OR TAB_GDT ; OEM specific selector +USER1_GSEL equ 130h OR TAB_GDT ; USER data structure + +.list ; end of VDMSEL.INC + \ No newline at end of file diff --git a/v4.0/src/MEMM/MEMM/VM386.INC b/v4.0/src/MEMM/MEMM/VM386.INC new file mode 100644 index 0000000..19ce94e --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VM386.INC @@ -0,0 +1,206 @@ + + +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM - MICROSOFT Expanded Memory Manager 386 +; +; Module: VM386.INC +; +; Version: 0.03 +; +; Date: May 12, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; Original +; 05/12/86 A Cleanup and segment reorganization +; 06/08/86 B Added Disable A20 equates +; 06/14/86 C Added MOV_CDTR_FRAME, PROT_INS_FRAME, and changed +; VTFO from 2 to 4 to reflect push of EBP from BP +; 06/15/86 D Added GPFAULT_FRAME +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/01/86 0.03 Added structures for accessing memory +; +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +; +; Structures for accessing memory +; +WordS struc + LowByte db ? + HighByte db ? +WordS ends + +DwordS struc + LowWord dw ? + HighWord dw ? +DwordS ends + +; +; Structure for accessing stack frame pushed during trap exit from VM +; + +VM_TRAP_FRAME struc +VMTF_EIP dw ? ; EIP (low) + dw ? ; EIP (high) +VMTF_CS dw ? ; CS + dw ? ; (padding) +VMTF_EFLAGS dw ? ; EFLAGS (low) +VMTF_EFLAGShi dw ? ; EFLAGS (high) +VMTF_ESP dw ? ; ESP (low) + dw ? ; ESP (high) +VMTF_SS dw ? ; SS + dw ? ; (padding) +VMTF_ES dw ? ; ES + dw ? ; (padding) +VMTF_DS dw ? ; DS + dw ? ; (padding) +VMTF_FS dw ? ; FS + dw ? ; (padding) +VMTF_GS dw ? ; GS + dw ? ; (padding) +VM_TRAP_FRAME ends +; + ; Used in EmMovCDTR (vminst.asm) +MOV_CDTR_FRAME struc +MCF_WBP dw ? ; Work BP +MCF_WES dw ? ; Work ES +MCF_EAX dw ? ; EAXlo + dw ? ; EAXhi +MCF_ESI dw ? ; ESIlo + dw ? ; ESIhi +MCF_EBX dw ? ; EBXlo + dw ? ; EBXhi +MCF_EBP dw ? ; EBPlo + dw ? ; EBPhi +MCF_VMERR dw ? ; VM Error Code (low) + dw ? ; VM Error Code (high) +MCF_VMEIP dw ? ; VM EIP (low) + dw ? ; VM EIP (high) +MCF_VMCS dw ? ; VM CS + dw ? ; (padding) +MCF_VMEFLAGS dw ? ; VM EFLAGS (low) +MCF_VMEFLAGShi dw ? ; VM EFLAGS (high) +MCF_VMESP dw ? ; VM ESP (low) + dw ? ; VM ESP (high) +MCF_VMSS dw ? ; VM SS + dw ? ; (padding) +MCF_VMES dw ? ; VM ES + dw ? ; (padding) +MCF_VMDS dw ? ; VM DS + dw ? ; (padding) +MCF_VMFS dw ? ; VM FS + dw ? ; (padding) +MCF_VMGS dw ? ; VM GS + dw ? ; (padding) +MOV_CDTR_FRAME ends +; + ; Used in EmProtIns (vminst.asm) +PROT_INS_FRAME struc +PIF_WBP dw ? ; Work BP +PIF_WES dw ? ; Work ES +PIF_AX dw ? ; EAXlo +PIF_DX dw ? ; EDXlo +PIF_ESI dw ? ; ESIlo + dw ? ; ESIhi +PIF_EBX dw ? ; EBXlo + dw ? ; EBXhi +PIF_EBP dw ? ; EBPlo + dw ? ; EBPhi +PIF_VMERR dw ? ; VM Error Code (low) + dw ? ; VM Error Code (high) +PIF_VMEIP dw ? ; VM EIP (low) + dw ? ; VM EIP (high) +PIF_VMCS dw ? ; VM CS + dw ? ; (padding) +PIF_VMEFLAGS dw ? ; VM EFLAGS (low) +PIF_VMEFLAGShi dw ? ; VM EFLAGS (high) +PIF_VMESP dw ? ; VM ESP (low) + dw ? ; VM ESP (high) +PIF_VMSS dw ? ; VM SS + dw ? ; (padding) +PIF_VMES dw ? ; VM ES + dw ? ; (padding) +PIF_VMDS dw ? ; VM DS + dw ? ; (padding) +PIF_VMFS dw ? ; VM FS + dw ? ; (padding) +PIF_VMGS dw ? ; VM GS + dw ? ; (padding) +PROT_INS_FRAME ends +; +GPFAULT_FRAME struc +GPF_ESI dw ? ; ESIlo + dw ? ; ESIhi +GPF_EBX dw ? ; EBXlo + dw ? ; EBXhi +GPF_EBP dw ? ; EBPlo + dw ? ; EBPhi +GPFAULT_FRAME ends +; +; The following constants define the offset of the Virtual Mode trap stack +; frame (from current SP assuming BP has been pushed) for the two cases: +; 1) exceptions that don't push error codes and 2) those that do. +; +VTFO equ 4 ; offset of VM trap stack frame +VTFOE equ VTFO + 4 ; as above, but including error code +; +; These constants are used to sanity-check the value of SP when one of +; the exception handlers has been entered: +; +STACK segment + extrn kstack_top:byte +STACK ends + + ; Trap/no error +VMT_STACK equ offset STACK:kstack_top - size VM_TRAP_FRAME - VTFO + ; Trap w/error +VMTERR_STACK equ offset STACK:kstack_top - size VM_TRAP_FRAME - VTFOE + +;****************************************************************************** +; E R R O R C O D E S +;****************************************************************************** +; +PrivErr equ 0000h ; Privileged Operation Error class +ErrLGDT equ 0000h ; Client tried to execute a LGDT +ErrLIDT equ 0001h ; Client tried to execute a LIDT +ErrLMSW equ 0002h ; Client tried to execute a LMSW +Err2LL equ 0003h ; Client tried to execute a 286 Loadall +Err3LL equ 0004h ; Client tried to execute a 386 Loadall +ErrMovCR equ 0005h ; Client tried to execute a CRn mov +ErrMovDR equ 0006h ; Client tried to execute a DRn mov +ErrMovTR equ 0007h ; Client tried to execute a TRn mov + +ExcpErr equ 0001h ; Exception Error class +ErrDIV equ 0000h ; Divide Error +ErrINT1 equ 0001h ; Debug Exception +ErrNMI equ 0002h ; NMI +ErrINT3 equ 0003h ; Int 3 +ErrINTO equ 0004h ; Int O error +ErrBounds equ 0005h ; Array Bounds Check +ErrOpCode equ 0006h ; Invalid Opcode +ErrCoPNA equ 0007h ; Coprocessor Device not available +ErrDouble equ 0008h ; Double Fault +ErrCoPseg equ 0009h ; Coprocessor Segment Overrun +ErrTSS equ 000Ah ; Invalid TSS +ErrSegNP equ 000Bh ; Segment not Present +ErrStack equ 000Ch ; Stack Fault +ErrGP equ 000Dh ; General Protection Fault +ErrPage equ 000Eh ; Page Fault +ErrCoPerr equ 0010h ; Coprocessor Error +ErrWrite equ 0020h ; Attempt to write to protected area +ErrDMA equ 0021h ; Attempt to DMA into page frame (not for user) +ErrINTProt equ 0022h ; General Protected interrupt error + +.list ; end of VM386.INC diff --git a/v4.0/src/MEMM/MEMM/VMINIT.ASM b/v4.0/src/MEMM/MEMM/VMINIT.ASM new file mode 100644 index 0000000..5b69b1a --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VMINIT.ASM @@ -0,0 +1,292 @@ + + +page 58,132 +;****************************************************************************** + title VMINIT.ASM - Initialization routines for VM-DOS +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: VMINIT - Initialization routines for MEMM/ VDM +; +; Version: 0.04 +; +; Date: January 30, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 01/30/86 Original +; 04/07/86 A Added InitBitMap +; 05/12/86 B Cleanup and segment reorganization +; 06/18/86 0.01 Re-arranged comments, etc. +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/03/86 0.03 Added call to Kybd_Watch +; 07/06/86 0.04 changed assume to DGROUP +; 07/30/86 0.06 removed PortClear reference +; +;****************************************************************************** +; +; Functional Description: +; +; This module contains various initialization routines for Virtual DOS +; +;****************************************************************************** +.386p +.lfcond ; list false conditionals + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public vminit ; module label + public InitBitMap ; init I/O Bit Map + public PortTrap ; set bit(s) in I/O Bit Map +ifdef oldstuff + public PortClear ; clear bit(s) in I/O Bit Map +endif + public BitOFF ; bit offset calculation + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; + include VDMseg.inc + include VDMsel.inc + include desc.inc + include elim.inc +FALSE equ 0 +TRUE equ not FALSE + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +ABS0 segment at 0000h +ABS0 ends + +TSS segment + + extrn IOBitMap:byte ; Bit Map in Tss + +TSS ends + + +_TEXT segment + + extrn A20_Trap_Init:near ; (a20trap.asm) + extrn RR_Trap_Init:near ; (RRtrap.asm) + extrn OEM_Trap_Init:near ; (OEMProc.asm) + +_TEXT ends +; +; +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** +; +_DATA segment +; +_DATA ends + +; +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +;------------------------------------------------------------------------------ +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP +vminit label byte + page +;****************************************************************************** +; InitBitMap - Initialize 386 Tss I/O bit map for Virtual mode I/O trapping. +; +; ENTRY: Real Mode +; DS = DGROUP +; I/O bit map all zeroes (no trapping) except last byte. +; EXIT: Real Mode +; I/O bit map in Tss initialized. +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +InitBitMap proc far +; + push ax + push bx + push si + push es +; + mov ax,seg TSS + mov es,ax ; set ES to I/O Bit Map seg + ASSUME ES:TSS + xor bx,bx ; ES:[BX] = pts to TSS +; +; initialize BitMapBase in Tss +; + mov ax,offset TSS:IOBitMap + mov ES:[bx.BitMapBase],ax ; set Bit Map base in Tss +; +; set ports for return to real trap +; + call RR_Trap_Init +; +; Turn on Keyboard watching for A20 disable +; + call A20_Trap_Init +; +; Turn on any other OEM specific trapping +; + call OEM_Trap_Init + +IB_exit: + pop es + ASSUME ES:DGROUP + pop si + pop bx + pop ax + ret ; *** RETURN *** +InitBitMap endp + +;****************************************************************************** +; PortTrap - sets bit(s) in I/O bit map to enable trapping at an I/O address +; +; This function sets the appropriate bits in the I/O bit map to enable +; trapping of the desired I/O address. Since some I/O ports on the AT system +; board are selected via only 10 bits of address lines, these ports appear +; at every 1K in the I/O address space. When trapping these "system board" +; ports, the trap bits in the I/O bit map must be set for every 1k instance +; of the port. +; +; ENTRY: AX = byte I/O address to set in Bit Map +; BH = high bit set => set traps bits for this address @ every 1K +; ES = TSS +; +; EXIT: none. +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +PortTrap proc near +; + ASSUME ES:TSS + push ax + push bx + push cx +; + mov cx,1 ; once by default + test bh,80h ;Q: map it every 1K ? + jz PT_loop ; N: do it once + mov cx,64 ; Y: do it 64 times (once per 1k) +PT_loop: + push ax ; map it. save this address + call BitOFF ; get offset and bit + or ES:IOBitMap[bx],al ; trap this address + pop ax ; restore this address + add ax,400h ; add 1k for next address + loop PT_loop ; and continue ... +; + pop cx + pop bx + pop ax + ret + ASSUME ES:DGROUP +; +PortTrap endp + + +ifdef oldstuff +;****************************************************************************** +; PortClear - clears bit(s) in I/O bit map to disable trapping at an I/O +; address +; +; This function clears the appropriate bits in the I/O bit map to disable +; trapping of the desired I/O address. Since some I/O ports on the AT system +; board are selected via only 10 bits of address lines, these ports appear +; at every 1K in the I/O address space. When clearing these "system board" +; ports, the trap bits in the I/O bit map must be cleared at every 1k instance +; of the port. +; +; ENTRY: AX = byte I/O address to clear in Bit Map +; BH = high bit set => clear traps bits for this address @ every 1K +; ES = data segment for I/O bit map +; +; EXIT: none. +; +; USED: Flags +; STACK: +; NOTE: This implementation does not account for a port being multiply set +; for many purposes. (ie. If a port is set 3 times, it still only takes one +; PortClear call to clear it.) If this is a problem, a counter for each +; enabled port will have to be added. +; +;------------------------------------------------------------------------------ +PortClear proc near +; + ASSUME ES:TSS + push ax + push bx + push cx +; + mov cx,1 ; once by default + test bh,80h ;Q: map it every 1K ? + jz PC_loop ; N: do it once + mov cx,64 ; Y: do it 64 times (once per 1k) +PC_loop: + push ax ; map it. save this address + call BitOFF ; get offset and bit + not al + and ES:IOBitMap[bx],al ; clear this address + pop ax ; restore this address + add ax,400h ; add 1k for next address + loop PC_loop ; and continue ... +; + pop cx + pop bx + pop ax + ret + ASSUME ES:DGROUP +; +PortClear endp +endif ; oldstuff + + +;****************************************************************************** +; BitOFF - sets up byte and bit for I/O address in I/O Bit Map +; +; ENTRY: AX = byte I/O address to set in Bit Map +; +; EXIT: BX = byte offset +; AL = bit to OR in to set proper bit +; +; USED: Flags +; STACK: +;------------------------------------------------------------------------------ +BitOFF proc near +; + push cx + + mov cx,ax + and cx,07h ; CL = bit pos for this port + shr ax,3 ; AX = byte offset for this bit + mov bx,ax ; BX = byte offset for port + mov ax,1 + shl ax,cl ; AL = bit mask for this port + + pop cx + ret +; +BitOFF endp + +; +_TEXT ends ; end of segment +; + end ; end of module diff --git a/v4.0/src/MEMM/MEMM/VMINST.ASM b/v4.0/src/MEMM/MEMM/VMINST.ASM new file mode 100644 index 0000000..9b1a5c7 --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VMINST.ASM @@ -0,0 +1,2135 @@ + + +page 58,132 +;****************************************************************************** + title VMINST.ASM - Virtual Mode GP fault instruction emulation +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: VMINST.ASM - Virtual Mode GP fault instruction emulation +; +; Version: 0.07 +; +; Date: February 11, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 02/12/86 Original +; 04/07/86 A- Added call to LIM emulation routines for all I/O. +; Bit Map set up to trap only LIM related ports. SBP. +; 05/12/86 B Cleanup and segment reorganization +; 05/18/86 C Added VM privileged instruction emulation +; 06/08/86 D Added calls to RRTrap. +; 06/14/86 E Changed stack saves from BP, BX, SI to EBP, EBX, ESI +; 06/15/86 F Changed inc [bp.VTFOE+VMTF_EIP] to inc SI in Prefix +; Handlers +; 06/15/86 G Added MOVSB and MOVSW for Rash Rule emulation +; 06/16/86 H Added Error Handler interfaces, BugMode conditional +; assembly constructs, and Error Handler return logic +; 06/19/86 0.01 Changed call JumpReal to jmp JumpReal +; 06/19/86 0.01 Clear TF bit on all INT reflects, but not on emulations. +; 06/19/86 0.01 CLTS now does a clts for the VM client. +; 06/27/86 0.02 INT3 emulation now ALLWAYS reflects +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/01/86 0.03 Call to IO_Trap instead of LIM_Trap +; 07/03/86 0.03 Let IO_Trap handle A20 and Return to real logic +; 07/05/86 0.04 JumpReal in R_CODE +; 07/06/86 0.04 changed assume to DGROUP +; 07/10/86 0.05 added MB_Flag check for move block emulator +; 07/30/86 0.06 removed PortClear reference +; 08/05/86 0.07 Changed EmHalt to really HLT if user IF=0 +; 07/20/88 Removed debugger codes (pc) +; +;****************************************************************************** +; +; Functional Description: +; +; This module contains the routines that handle GP faults fielded from +; Virtual Mode. The offending instruction is either emulated or we exit +; to the debugger. +; +; NOTE: The current implementation is sufficient for breadboard - see +; 'to do' notes in various header for holes. Specifically, the only +; override that is handled is REP, and only for INS/OUTS. Segment +; overrides are not yet supported. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public VmInst ; module label + public VmFault + public EmProtIns ; just for debug map + public EmMovCDTR ; just for debug map + public EmMOVSW ; just for debug map +; +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +R_CODE segment + extrn JumpReal:far ; cont client in RM (rrtrap.asm) + extrn MB_Flag:byte ; non-zero => do move block +R_CODE ends + +_TEXT segment + extrn IO_Trap:near ; I/O Trap Dispatcher + extrn EM286ll:near ; 286 loadall emulator (EM286LL) + extrn EM386ll:near ; 386 loadall emulator (EM386LL) + extrn Move_Block:near ; Int 15h move block function (MOVEB) + extrn hw_int:near ; HW-ROM reflection code (VMTRAP) + extrn ErrHndlr:near ; Handle user's error response + extrn MapLinear:near ; map linear address + extrn UnMapLinear:near ; unmap linear address +_TEXT ends + + page +;****************************************************************************** +; I N C L U D E F I L E S +;****************************************************************************** + +include VDMseg.inc +include desc.inc +include VDMsel.inc +include vm386.inc +include loadall.inc +include instr386.inc +include oemdep.inc +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +FALSE equ 0 +TRUE equ not FALSE + +LOCK_PREFIX equ 0F0h + +IF_FLAG equ 0200h ; IF bit in flags +DF_FLAG equ 0400h ; DF bit in flags + +; +; bit flags for instruction prefixes +; +REP_FLAG equ 0001h +REPNE_FLAG equ 0002h +REPS_FLAG equ (REP_FLAG or REPNE_FLAG) +CS_FLAG equ 0004h +DS_FLAG equ 0008h +ES_FLAG equ 0010h +SS_FLAG equ 0020h +FS_FLAG equ 0040h +GS_FLAG equ 0080h +LOCK_FLAG equ 0100h +OPER_SZ_FLAG equ 0200h +ADDR_SZ_FLAG equ 0400h +P0F_FLAG equ 0800h + +page +;****************************************************************************** +; L O C A L D A T A A R E A +;****************************************************************************** +_DATA segment + +PrefixFlag dw 0 ; flags for Fault Instr Prefixes +RefNum dw 0 ; Reflect number for RefToRom + +_DATA ends + +page +;****************************************************************************** +; C O D E A R E A +;****************************************************************************** +_TEXT segment + assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP + +VmInst label byte +; +; Index table for opcode emulation dispatch - This is too general-purpose +; if all we want to handle is INT instructions, but it'll get fleshed out +; later, when we start emulating IOPL-sensitive stuff +; +; the directive below is giving problems because this segment is byte aligned +; will fix it..sunilp +; EVEN ; word aligning should make execution + ; faster +OpTable label word + dw offset _TEXT:BadVmTrap ; 0 - LLDT, LTR, SLDT, STR, VERR, VERW + dw offset _TEXT:EmProtIns ; 1 - LGDT, LIDT, LMSW + dw offset _TEXT:BadVmTrap ; 2 - LAR + dw offset _TEXT:BadVmTrap ; 3 - LSL + dw offset _TEXT:BadVmTrap ; 4 + dw offset _TEXT:EmLoadal2 ; 5 - 286Loadall + dw offset _TEXT:EmCLTS ; 6 - CLTS + dw offset _TEXT:EmLoadal3 ; 7 - 386Loadall + dw offset _TEXT:BadVmTrap ; 8 + dw offset _TEXT:BadVmTrap ; 9 + dw offset _TEXT:BadVmTrap ; a + dw offset _TEXT:BadVmTrap ; b + dw offset _TEXT:BadVmTrap ; c + dw offset _TEXT:BadVmTrap ; d + dw offset _TEXT:BadVmTrap ; e + dw offset _TEXT:Prefix_0F ; f + dw offset _TEXT:BadVmTrap ; 10 + dw offset _TEXT:BadVmTrap ; 11 + dw offset _TEXT:BadVmTrap ; 12 + dw offset _TEXT:BadVmTrap ; 13 + dw offset _TEXT:BadVmTrap ; 14 + dw offset _TEXT:BadVmTrap ; 15 + dw offset _TEXT:BadVmTrap ; 16 + dw offset _TEXT:BadVmTrap ; 17 + dw offset _TEXT:BadVmTrap ; 18 + dw offset _TEXT:BadVmTrap ; 19 + dw offset _TEXT:BadVmTrap ; 1a + dw offset _TEXT:BadVmTrap ; 1b + dw offset _TEXT:BadVmTrap ; 1c + dw offset _TEXT:BadVmTrap ; 1d + dw offset _TEXT:BadVmTrap ; 1e + dw offset _TEXT:BadVmTrap ; 1f + dw offset _TEXT:EmMovCDTR ; 20 - Mov Rn, CRn + dw offset _TEXT:EmMovCDTR ; 21 - Mov Rn, DRn + dw offset _TEXT:EmMovCDTR ; 22 - Mov CRn, Rn + dw offset _TEXT:EmMovCDTR ; 23 - Mov DRn, Rn + dw offset _TEXT:EmMovCDTR ; 24 - Mov Rn, TRn + dw offset _TEXT:BadVmTrap ; 25 + dw offset _TEXT:ESOverride ; 26 - ES Override & Mov TRn, Rn + dw offset _TEXT:BadVmTrap ; 27 + dw offset _TEXT:BadVmTrap ; 28 + dw offset _TEXT:BadVmTrap ; 29 + dw offset _TEXT:BadVmTrap ; 2a + dw offset _TEXT:BadVmTrap ; 2b + dw offset _TEXT:BadVmTrap ; 2c + dw offset _TEXT:BadVmTrap ; 2d + dw offset _TEXT:CSOverride ; 2e - CS Override + dw offset _TEXT:BadVmTrap ; 2f + dw offset _TEXT:BadVmTrap ; 30 + dw offset _TEXT:BadVmTrap ; 31 + dw offset _TEXT:BadVmTrap ; 32 + dw offset _TEXT:BadVmTrap ; 33 + dw offset _TEXT:BadVmTrap ; 34 + dw offset _TEXT:BadVmTrap ; 35 + dw offset _TEXT:SSOverride ; 36 - SS Override + dw offset _TEXT:BadVmTrap ; 37 + dw offset _TEXT:BadVmTrap ; 38 + dw offset _TEXT:BadVmTrap ; 39 + dw offset _TEXT:BadVmTrap ; 3a + dw offset _TEXT:BadVmTrap ; 3b + dw offset _TEXT:BadVmTrap ; 3c + dw offset _TEXT:BadVmTrap ; 3d + dw offset _TEXT:DSOverride ; 3e - DS Override + dw offset _TEXT:BadVmTrap ; 3f + dw offset _TEXT:BadVmTrap ; 40 + dw offset _TEXT:BadVmTrap ; 41 + dw offset _TEXT:BadVmTrap ; 42 + dw offset _TEXT:BadVmTrap ; 43 + dw offset _TEXT:BadVmTrap ; 44 + dw offset _TEXT:BadVmTrap ; 45 + dw offset _TEXT:BadVmTrap ; 46 + dw offset _TEXT:BadVmTrap ; 47 + dw offset _TEXT:BadVmTrap ; 48 + dw offset _TEXT:BadVmTrap ; 49 + dw offset _TEXT:BadVmTrap ; 4a + dw offset _TEXT:BadVmTrap ; 4b + dw offset _TEXT:BadVmTrap ; 4c + dw offset _TEXT:BadVmTrap ; 4d + dw offset _TEXT:BadVmTrap ; 4e + dw offset _TEXT:BadVmTrap ; 4f + dw offset _TEXT:BadVmTrap ; 50 + dw offset _TEXT:BadVmTrap ; 51 + dw offset _TEXT:BadVmTrap ; 52 + dw offset _TEXT:BadVmTrap ; 53 + dw offset _TEXT:BadVmTrap ; 54 + dw offset _TEXT:BadVmTrap ; 55 + dw offset _TEXT:BadVmTrap ; 56 + dw offset _TEXT:BadVmTrap ; 57 + dw offset _TEXT:BadVmTrap ; 58 + dw offset _TEXT:BadVmTrap ; 59 + dw offset _TEXT:BadVmTrap ; 5a + dw offset _TEXT:BadVmTrap ; 5b + dw offset _TEXT:BadVmTrap ; 5c + dw offset _TEXT:BadVmTrap ; 5d + dw offset _TEXT:BadVmTrap ; 5e + dw offset _TEXT:BadVmTrap ; 5f + dw offset _TEXT:BadVmTrap ; 60 + dw offset _TEXT:BadVmTrap ; 61 + dw offset _TEXT:BadVmTrap ; 62 +; +; ARPL is used to return from virtual mode to protected mode for use in MEMM +; + dw offset _TEXT:ReturnEMM ; 63 - ARPL (return to Protected mode gateway) + dw offset _TEXT:FSOverride ; 64 - FS override + dw offset _TEXT:GSOverride ; 65 - GS override + dw offset _TEXT:BadVmTrap ; 66 - Operand size override + dw offset _TEXT:BadVmTrap ; 67 - Address size override + dw offset _TEXT:BadVmTrap ; 68 + dw offset _TEXT:BadVmTrap ; 69 + dw offset _TEXT:BadVmTrap ; 6a + dw offset _TEXT:BadVmTrap ; 6b + dw offset _TEXT:EmINSB ; 6c - INSB + dw offset _TEXT:EmINSW ; 6d - INSW + dw offset _TEXT:EmOUTSB ; 6e - OUTSB + dw offset _TEXT:EmOUTSW ; 6f - OUTSW + dw offset _TEXT:BadVmTrap ; 70 + dw offset _TEXT:BadVmTrap ; 71 + dw offset _TEXT:BadVmTrap ; 72 + dw offset _TEXT:BadVmTrap ; 73 + dw offset _TEXT:BadVmTrap ; 74 + dw offset _TEXT:BadVmTrap ; 75 + dw offset _TEXT:BadVmTrap ; 76 + dw offset _TEXT:BadVmTrap ; 77 + dw offset _TEXT:BadVmTrap ; 78 + dw offset _TEXT:BadVmTrap ; 79 + dw offset _TEXT:BadVmTrap ; 7a + dw offset _TEXT:BadVmTrap ; 7b + dw offset _TEXT:BadVmTrap ; 7c + dw offset _TEXT:BadVmTrap ; 7d + dw offset _TEXT:BadVmTrap ; 7e + dw offset _TEXT:BadVmTrap ; 7f + dw offset _TEXT:BadVmTrap ; 80 + dw offset _TEXT:BadVmTrap ; 81 + dw offset _TEXT:BadVmTrap ; 82 + dw offset _TEXT:BadVmTrap ; 83 + dw offset _TEXT:BadVmTrap ; 84 + dw offset _TEXT:BadVmTrap ; 85 + dw offset _TEXT:BadVmTrap ; 86 + dw offset _TEXT:BadVmTrap ; 87 + dw offset _TEXT:BadVmTrap ; 88 + dw offset _TEXT:BadVmTrap ; 89 + dw offset _TEXT:BadVmTrap ; 8a + dw offset _TEXT:BadVmTrap ; 8b + dw offset _TEXT:BadVmTrap ; 8c + dw offset _TEXT:BadVmTrap ; 8d + dw offset _TEXT:BadVmTrap ; 8e + dw offset _TEXT:BadVmTrap ; 8f + dw offset _TEXT:BadVmTrap ; 90 + dw offset _TEXT:BadVmTrap ; 91 + dw offset _TEXT:BadVmTrap ; 92 + dw offset _TEXT:BadVmTrap ; 93 + dw offset _TEXT:BadVmTrap ; 94 + dw offset _TEXT:BadVmTrap ; 95 + dw offset _TEXT:BadVmTrap ; 96 + dw offset _TEXT:BadVmTrap ; 97 + dw offset _TEXT:BadVmTrap ; 98 + dw offset _TEXT:BadVmTrap ; 99 + dw offset _TEXT:BadVmTrap ; 9a + dw offset _TEXT:BadVmTrap ; 9b + dw offset _TEXT:BadVmTrap ; 9c - PUSHF (not for IOPL=3) + dw offset _TEXT:BadVmTrap ; 9d - POPF (not for IOPL=3) + dw offset _TEXT:BadVmTrap ; 9e + dw offset _TEXT:BadVmTrap ; 9f + dw offset _TEXT:BadVmTrap ; a0 + dw offset _TEXT:BadVmTrap ; a1 + dw offset _TEXT:BadVmTrap ; a2 + dw offset _TEXT:BadVmTrap ; a3 + dw offset _TEXT:BadVmTrap ; a4 - MOVSB + dw offset _TEXT:EmMOVSW ; a5 - MOVSW + dw offset _TEXT:BadVmTrap ; a6 + dw offset _TEXT:BadVmTrap ; a7 + dw offset _TEXT:BadVmTrap ; a8 + dw offset _TEXT:BadVmTrap ; a9 + dw offset _TEXT:BadVmTrap ; aa + dw offset _TEXT:BadVmTrap ; ab + dw offset _TEXT:BadVmTrap ; ac + dw offset _TEXT:BadVmTrap ; ad + dw offset _TEXT:BadVmTrap ; ae + dw offset _TEXT:BadVmTrap ; af + dw offset _TEXT:BadVmTrap ; b0 + dw offset _TEXT:BadVmTrap ; b1 + dw offset _TEXT:BadVmTrap ; b2 + dw offset _TEXT:BadVmTrap ; b3 + dw offset _TEXT:BadVmTrap ; b4 + dw offset _TEXT:BadVmTrap ; b5 + dw offset _TEXT:BadVmTrap ; b6 + dw offset _TEXT:BadVmTrap ; b7 + dw offset _TEXT:BadVmTrap ; b8 + dw offset _TEXT:BadVmTrap ; b9 + dw offset _TEXT:BadVmTrap ; ba + dw offset _TEXT:BadVmTrap ; bb + dw offset _TEXT:BadVmTrap ; bc + dw offset _TEXT:BadVmTrap ; bd + dw offset _TEXT:BadVmTrap ; be + dw offset _TEXT:BadVmTrap ; bf + dw offset _TEXT:BadVmTrap ; c0 + dw offset _TEXT:BadVmTrap ; c1 + dw offset _TEXT:BadVmTrap ; c2 + dw offset _TEXT:BadVmTrap ; c3 + dw offset _TEXT:BadVmTrap ; c4 + dw offset _TEXT:BadVmTrap ; c5 + dw offset _TEXT:BadVmTrap ; c6 + dw offset _TEXT:BadVmTrap ; c7 + dw offset _TEXT:BadVmTrap ; c8 + dw offset _TEXT:BadVmTrap ; c9 + dw offset _TEXT:BadVmTrap ; ca + dw offset _TEXT:BadVmTrap ; cb + dw offset _TEXT:EmINT3 ; cc - INT 3 + dw offset _TEXT:EmINTnn ; cd - INT nn + dw offset _TEXT:EmINTO ; ce - INTO + dw offset _TEXT:BadVmTrap ; cf - IRET/EmIRET (not for IOPL=3) + dw offset _TEXT:BadVmTrap ; d0 + dw offset _TEXT:BadVmTrap ; d1 + dw offset _TEXT:BadVmTrap ; d2 + dw offset _TEXT:BadVmTrap ; d3 + dw offset _TEXT:BadVmTrap ; d4 + dw offset _TEXT:BadVmTrap ; d5 + dw offset _TEXT:BadVmTrap ; d6 + dw offset _TEXT:BadVmTrap ; d7 + dw offset _TEXT:BadVmTrap ; d8 + dw offset _TEXT:BadVmTrap ; d9 + dw offset _TEXT:BadVmTrap ; da + dw offset _TEXT:BadVmTrap ; db + dw offset _TEXT:BadVmTrap ; dc + dw offset _TEXT:BadVmTrap ; dd + dw offset _TEXT:BadVmTrap ; de + dw offset _TEXT:BadVmTrap ; df + dw offset _TEXT:BadVmTrap ; e0 + dw offset _TEXT:BadVmTrap ; e1 + dw offset _TEXT:BadVmTrap ; e2 + dw offset _TEXT:BadVmTrap ; e3 + dw offset _TEXT:EmINBimm ; e4 - INB imm + dw offset _TEXT:EmINWimm ; e5 - INW imm + dw offset _TEXT:EmOUTBimm ; e6 - OUTB imm + dw offset _TEXT:EmOUTWimm ; e7 - OUTW imm + dw offset _TEXT:BadVmTrap ; e8 + dw offset _TEXT:BadVmTrap ; e9 + dw offset _TEXT:BadVmTrap ; ea + dw offset _TEXT:BadVmTrap ; eb + dw offset _TEXT:EmINB ; ec - INB + dw offset _TEXT:EmINW ; ed - INW + dw offset _TEXT:EmOUTB ; ee - OUTB + dw offset _TEXT:EmOUTW ; ef - OUTW + dw offset _TEXT:EmLOCK ; f0 - LOCK + dw offset _TEXT:BadVmTrap ; f1 + dw offset _TEXT:EmREPNE ; f2 - REPNE + dw offset _TEXT:EmREP ; f3 - REP/REPE + dw offset _TEXT:EmHALT ; f4 - HLT + dw offset _TEXT:BadVmTrap ; f5 + dw offset _TEXT:BadVmTrap ; f6 + dw offset _TEXT:BadVmTrap ; f7 + dw offset _TEXT:BadVmTrap ; f8 + dw offset _TEXT:BadVmTrap ; f9 + dw offset _TEXT:BadVmTrap ; fa - CLI EmCLI (not for IOPL=3) + dw offset _TEXT:BadVmTrap ; fb - STI EmSTI (not for IOPL=3) + dw offset _TEXT:BadVmTrap ; fc + dw offset _TEXT:BadVmTrap ; fd + dw offset _TEXT:BadVmTrap ; fe + dw offset _TEXT:BadVmTrap ; ff - Change P0F_Invalid, if used + + page +;****************************************************************************** +; VmFault - entry point for Virtual Mode GP faults (from routine vm_trap0d +; in module VMTRAP.ASM). The appropriate instructions are emulated and +; control is returned to the Virtual Mode client. Currently, we assume +; the client is running WITH IOPL, INT gate DPL = 0, and a truncated +; IDT, so INT instruction fault to here and are emulated. All other +; GP faults enter the debugger. +; +; The following instructions are invalid in Real or Virtual Mode: +; +; ARPL, LAR, LSL, VERR, VERW, STR, LTR, SLDT, LLDT +; +; The following instructions are privileged and are thus invalid in +; Virtual Mode since VM progs run at CPL 3: +; +; LIDT, LDGT, LMSW, CLTS, HLT, Debug Register ops, Control +; Register ops, and Test Register ops +; +; If client does not have IOPL, the following instructions must be handled +; (in addition to the INT instructions). This scenario changes for B0: +; +; IN, INS, OUT, OUTS, STI, CLI, LOCK, PUSHF, POPF, and IRET +; +; For B0, the following instructions must be handled when they trap +; according to the bit map in the TSS. +; +; IN, INS, OUT, and OUTS +; +; For Invalid Opcode (vm_trap06) emulation: +; The following instructions are invalid in Real or Virtual Mode: +; +; LTR, LLDT, LAR, LSL, ARPL, STR, SLDT, VERR, VERW +; +; In fielding the exception from Virtual Mode, the 386 interrupt gate +; switched to the Ring 0 stack and pushed 32-bit values as follows: +; +; hiword loword offset (in addition to error code and BP push) +; +------+------+ <-------- Top of 'kernel' stack +; | 0000 | GS | +32 (decimal) +; |------+------| +; | 0000 | FS | +28 +; |------|------| +; | 0000 | DS | +24 +; |------|------| +; | 0000 | ES | +20 +; |------|------| +; | 0000 | SS | +16 +; |------|------| +; | ESP | +12 +; |------|------| +; | EFLAGS | +08 +; |------|------| +; | 0000 | CS | +04 +; |------|------| +; | EIP | +00 +; +------|------+ +; | error code | +; |------|------| <-------- Ring 0 SS:SP +; | (ebp) | +; +------+------+ <-------- Ring 0 SS:EBP +; +; +; ENTRY: 386 Protected Mode - ring 0 +; EBP is on the stack +; SS:BP -> VM trap frame on stack w/error code (faulting selector) +; GP exceptions are faults: pushed CS:EIP points to faulting opcode +; EXIT: via IRET to VM client, instruction emulated as necessary +; USED: (none) (note that DS & ES are free to use - saved during trap) +; STACK: n/a +;------------------------------------------------------------------------------ +VmFault proc near + PUSH_EBX ; local registers + PUSH_ESI + HwTabUnlock ; unlock high ram for gdt changes + mov bx,GDTD_GSEL ; get GDT data alias + mov ds,bx ; DS -> GDT +; +; Build a selector (VM1_GSEL) to client's stack. VM1_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; + mov bx,[bp.VTFOE+VMTF_SS] ; BX = VM SS (segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFOE+VMTF_SS] ; BX = VM SS (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM1_GSEL+4],bh ; place in descriptor +; +; Build a selector (VM2_GSEL) to client's code segment, as above. +; + mov bx,[bp.VTFOE+VMTF_CS] ; BX = VM CS (in segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM2_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFOE+VMTF_CS] ; BX = VM CS (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM2_GSEL+4],bh ; place in descriptor +; +; Reset prefix flags +; + mov bx,VDMD_GSEL + mov es,bx + mov ES:[PrefixFlag],0 ; start with no prefixes +; +; Jump to appropriate instruction handler +; + mov bx,VM2_GSEL + mov ds,bx ; DS = selector for VM code segment + mov si,[bp.VTFOE+VMTF_EIP] ; DS:SI = VM CS:IP +VmInsHandle: + mov bl,ds:[si] ; BL = opcode + mov bh,0 ; BX = opcode + shl bx,1 ; BX = BX*2 (word table) + ; DS:SI = VM CS:IP + ; ES pts to local data segment + ; VM1_GSEL pts to VM SS + ; VM2_GSEL pts to VM CS + jmp cs:OpTable[bx] ; enter instruction emulation routine + +VmFault endp + +page +;****************************************************************************** +; BadVmTrap - unsupported Virtual Mode GP exception - enter the debugger +; +; ENTRY: EBP,EBX,ESI are on the stack +; EXIT: to the debugger +; USED: +; STACK: n/a +;------------------------------------------------------------------------------ +BadVmTrap proc near + jmp Reflect6 ; Reflect to VM illegal opcode handler +BadVmTrap endp + +page +;****************************************************************************** +; ReturnEMM - user is trying to go back into the protected mode via ARPL +; +; ENTRY: EBP,EBX,ESI are on the stack +; EXIT: to the debugger +; USED: +; STACK: n/a +;------------------------------------------------------------------------------ +ReturnEMM proc near + add si, 2 ; "IP" now points to instruction + push si ; after "ARPL reg,reg" + ret ; back in protected mode! +ReturnEMM endp + +page +;****************************************************************************** +; EmINTnn - emulate software interrupt +; +; The emulation of the software INT instructions requires us to massage +; the trap stack frame (see VmFault header) and build a 'real mode' +; stack frame for the virtual mode client so that we can transfer +; control to virtual mode at the address specified in the appropriate +; real mode IDT vector. The client's IRET out of the interrupt routine +; will proceed normally (assuming we're letting him run with IOPL = 3). +; Since we're fielding the trap from Virtual Mode, we assume the high +; word of ESP and EIP is 0000. +; +; +-------+ <-------- Client's current SS:SP +; | Flags | +4 +; |-------| +; | CS | +2 +; |-------| +; | IP | +0 +; +-------+ <-------- Client's SS:SP when we let him have control +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = CD nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; appropriate real mode IRET set up @ client's SS:SP +; USED: (none) +; STACK: +; +; to do: Streamline this code - it's on the critical path +; Decide about how to handle Trace Bit in general +;------------------------------------------------------------------------------ +EmINTnn proc near + + inc si ; DS:SI -> nn (int #) + +; Check for Int15 (Move Block call) + cmp byte ptr [si], 15h + jne NotInt15 + cmp ah,87h ;Q: is this a move block call ? + jne NotInt15 ; N: process as normal interrupt + mov bx,RCODEA_GSEL ; Y: check local flag + mov ds,bx ; DS -> R_CODE seg + ASSUME DS:R_CODE + cmp [MB_Flag],0 ; Q: do we see this move block ? + je NotInt15 ; N: process as normal int + ; Y: emulate move block + ; set up VM1_GSEL to point to ES:0 from + ; Virtual Mode + ;NOTE: DS -> R_CODE + inc si + mov [bp.VTFOE+VMTF_EIP], si ; point beyond int6 instr + mov bx,GDTD_GSEL + mov es,bx ; ES pts to GDT + mov bx,[bp.VTFOE+VMTF_ES] ; BX = ES seg addr + shl bx,4 ; BX = low 16 bits of ES addr + mov es:[VM1_GSEL+2],bx ; set low 16 bits of ES base addr + mov bx,[bp.VTFOE+VMTF_ES] ; BX = ES seg addr again + shr bx,4 ; BH = high 8 bits of ES addr + mov es:[VM1_GSEL+4],bh ; place in descriptor + + mov bx,VM1_GSEL + mov es,bx ; ES pts to VM ES area + + mov bx,sp ; SS:BX -> GP Fault stack frame + mov si,SS:[bx.GPF_ESI] ; ES:SI pts to caller's gdt + call move_block ; move block function + mov ds:[MB_Flag],0 ; turn off flag !! + + ASSUME DS:DGROUP ; done with R_CODE + + jmp short EmSkipLockExit ; exit, but skip table lock. + ; move block MAY unlock tables. +; +; Adjust client's SP to make room for building his IRET frame +; +NotInt15: + sub word ptr [bp.VTFOE+VMTF_ESP],6 ; adjust client's SP + mov bx,VM1_GSEL + mov ds,bx ; DS = VM stack segment + mov si,[bp.VTFOE+VMTF_ESP] ; DS:SI -> client's IRET stack frame +; +; Move low 16 bits of Flags, CS, and EIP from IRET frame to client stack frame +; + mov bx,[bp.VTFOE+VMTF_EFLAGS] ; low word of EFLAGS +; +; *** Clear IF bit on flags for reflect, but leave it unchanged for the +; flags on the IRET stack we build on the client's stack +; *** Also clear the Trace Flag -> because all software INTs clear the trace +; flag. +; + and [bp.VTFOE+VMTF_EFLAGS],not 300h + + mov ds:[si.4],bx ; to client's flags + mov bx,[bp.VTFOE+VMTF_CS] ; + mov ds:[si.2],bx ; to client's CS + mov bx,[bp.VTFOE+VMTF_EIP] ; low word of EIP + add bx,2 ; set IP past the instruction we emulate + mov ds:[si.0],bx ; to client's IP +; +; Replace low 16 bits of IRET frame CS:EIP with vector from real mode IDT +; + mov si,VM2_GSEL + mov ds,si ; DS -> Client's code segment + mov bl,ds:[bx-1] ; get INTerrupt number + xor bh,bh ; BX has INT number + shl bx,2 ; BX = BX * 4 (vector table index) + mov si,RM_IDT_GSEL ; get real mode IDT alias + mov ds,si ; DS -> Real Mode IDT + mov si,ds:[bx] ; + mov [bp.VTFOE+VMTF_EIP],si ; move the IP + mov si,ds:[bx+2] ; + mov [bp.VTFOE+VMTF_CS],si ; move the CS +; +; 32-bit IRET back to client +; +EmExit: + HwTabLock ; enable the high ram hw protection +EmSkipLockExit: ; as the label implies... + POP_ESI ; restore local regs + POP_EBX + POP_EBP + add sp,4 ; throw away error code + OP32_IRET ; *** RETURN *** to client +EmINTnn endp + +page +;****************************************************************************** +; EmINT3 - emulate the 'breakpoint' interrupt instruction +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = CD nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; appropriate real mode IRET set up @ client's SS:SP +; USED: (none) +; STACK: +; +; to do: implement the handler +;------------------------------------------------------------------------------ +EmINT3 proc near + mov ES:[RefNum], 03h ; Vector to VM int 3 handler +RefIntN: + inc si ; fault, not a trap + mov [bp.VTFOE+VMTF_EIP], si ; point beyond int3 + jmp RefToRom ; and let the VM OS handle it +EmINT3 endp + +;****************************************************************************** +; EmINTO - emulate overflow interrupt +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = CD nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; appropriate real mode IRET set up @ client's SS:SP +; USED: (none) +; STACK: +;------------------------------------------------------------------------------ +EmINTO proc near + mov ES:[RefNum], 04h ; Vector to VM int 3 handler + jmp short RefIntN +EmINTO endp + +page +;****************************************************************************** +; EmINB - emulate the IN byte instruction +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; USED: +; STACK: n/a +;------------------------------------------------------------------------------ +EmINB proc near + inc si + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + push bx + xor bx,bx ; IN instruction + call IO_Trap ; Q: Emulated ? + jnc EINB_Exit ; Y: exit + in al,dx ; N:do the INput +EINB_Exit: + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmINB endp + +page +;****************************************************************************** +; EmINW - emulate IN word +; +; This routine emulates the IN word instruction +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +;------------------------------------------------------------------------------ +EmINW proc near + inc si + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + push bx + xor bx,bx ; IN instruction + call IO_Trap ; Q: Emulated ? + cbw ; AX= returned value + jnc EINW_Exit ; Y: exit + in ax,dx ; N:do the word INput +EINW_Exit: ; + pop bx ; + jmp EmExit ; *** RETURN *** to VM client +EmINW endp + +page +;****************************************************************************** +; EmINBimm - emulate IN word immediate +; +; This routine emulates the IN word immediate instruction +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +;------------------------------------------------------------------------------ +EmINBimm proc near + push bx + push dx + mov dl,ds:[si+1] ; get port number + xor dh,dh ; DX has INT number + add si, 2 + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + xor bx,bx ; IN instruction + call IO_Trap ; Q: Emulated ? + jnc EINBi_Exit ; Y: exit + in al,dx ; N:do the INput +EINBi_exit: + pop dx + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmINBimm endp + +page +;****************************************************************************** +;*** EmINWimm - emulate IN word immediate +; +; This routine emulates the IN word immediate instruction +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +;------------------------------------------------------------------------------ +EmINWimm proc near + push bx + push dx + mov dl,ds:[si+1] ; get port number + xor dh,dh ; DX has INT number + add si, 2 + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + xor bx,bx ; IN instruction + call IO_Trap ; Q: Emulated ? + cbw ; AX = returned value + jnc EINWi_Exit ; Y: exit + in ax,dx ; N:do the word INput +EINWi_Exit: + pop dx + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmINWimm endp + +page +;****************************************************************************** +;*** EmOUTB - emulate OUT byte +; +; This routine emulates the OUT byte instruction +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +EmOUTB proc near + inc si + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + push bx + push dx + mov bx,1 ; OUT instruction + call IO_Trap ; Q: Emulated ? + jnc EOUTB_Exit ; Y:exit +EOUTB_em: + out dx,al ; N:do the byte OUTput +EOUTB_Exit: + pop dx + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmOUTB endp + +page +;****************************************************************************** +;*** EmOUTW - emulate OUT word +; +; This routine emulates the OUT word instruction +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +EmOUTW proc near + inc si + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + push bx + mov bx,1 ; OUT instruction + call IO_Trap ; Q: Emulated ? + jnc EOUTW_Exit ; Y: exit + ; N: + out dx,ax ; do the word OUTput +EOUTW_Exit: + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmOUTW endp + +page +;****************************************************************************** +;*** EmOUTBimm - emulate OUT byte immediate +; +; This routine emulates the OUT byte immediate +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +EmOUTBimm proc near + push bx + push dx + mov dl,ds:[si+1] ; get port number + xor dh,dh ; DX has INT number + add si, 2 + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + mov bx,1 ; OUT instruction + call IO_Trap ; Q: Emulated ? + jnc EOUTBi_Exit ; Y:exit +EOUTBi_em: + out dx,al ; N:do the byte OUTput +EOUTBi_Exit: + pop dx + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmOUTBimm endp + +page +;****************************************************************************** +;*** EmOUTWimm - emulate OUT word immediate +; +; This routine emulates the OUT word immediate instruction +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +EmOUTWimm proc near + push bx + push dx + mov dl,ds:[si+1] ; get port number + xor dh,dh ; DX has INT number + add si, 2 + mov [bp.VTFOE+VMTF_EIP],si ; set IP past the instruction we emulate + mov bx,1 ; OUT instruction + call IO_Trap ; Q: Emulated ? + jnc EOUTWi_Exit ; Y: exit + out dx,ax ; N:do the word OUTput +EOUTWi_Exit: + pop dx + pop bx + jmp EmExit ; *** RETURN *** to VM client +EmOUTWimm endp +page +;****************************************************************************** +;*** EmHALT - Emulate HALT command +; +; This routine is entered if a faulting instruction +; is a HALT command +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT return to VM client unless client IF=0 then +; HLT is executed with IF=0 +; +EmHALT proc near + ; Q: client's IF bit is 0? + test word ptr [bp.VTFOE+VMTF_EFLAGS], IF_FLAG + jz EmDoHlt ; Y: execute HLT if IF=0 + inc si ; inc VM CS:IP past command + mov [bp.VTFOE+VMTF_EIP], si ; we emulate +; A halt on an INTEL architecture machine is just waiting for an interrupt +; We'll pretend an interrupt occurs after a short wait + push cx + mov cx,4000h + loop $ ; Wait awhile + pop cx + jmp EmExit ; then leave +emDoHlt: + cli + hlt ; Halt till NMI + jmp EmExit + +EmHALT endp + +page +;****************************************************************************** +;*** EmLoadal2 - Emulate 286 Loadall command +; +; This routine is entered if a faulting instruction +; is a Loadall 286 command +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT return to VM client +; +EmLoadal2 proc near + + test ES:[PrefixFlag],P0F_FLAG ; Q:Do we have the right prefix? + jz Not_Loadall + jmp EM286ll ; Y: emulate 286 loadall + +Not_Loadall: + jmp BadVmTrap ; N: Vector to VM illegal opcode + +EmLoadal2 endp + +;****************************************************************************** +;*** EmLoadal3 - Emulate 386 Loadall command +; +; This routine is entered if a faulting instruction +; is a Loadall 386 command +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT return to VM client +; +EmLoadal3 proc near + + test ES:[PrefixFlag],P0F_FLAG + jz Not_Loadall + jmp EM386ll ; Y: emulate 386 loadall + +EmLoadal3 endp + +;****************************************************************************** +; EmCLTS - emulate the CLTS instruction +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; USED: +; STACK: n/a +;------------------------------------------------------------------------------ +EmCLTS proc near + + test ES:[PrefixFlag],P0F_FLAG + jz Not_CLTS + clts ; go ahead and CLTS + inc si ; inc VM CS:IP past command + mov [bp.VTFOE+VMTF_EIP], si ; we emulate + jmp EmExit ; and leave + +Not_CLTS: + jmp BadVmTrap + +EmCLTS endp + +;****************************************************************************** +; EmProtIns - emulate the protection control instructions +; Currently this throws LIDT and LGDT to the error handler and only emulates +; LMSW +; NOTE: The Stack configuration is critical!!! If it is changed, the +; offsets to the register images must be updated accordingly. +; +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; bp.VTFOE+VMTF_EIP points beyond offender to next client instruction +; VM2_GSEL, DS, and SI may be modified at exit, this should not be a +; problem for the IRET +; USED: +; STACK: n/a +;------------------------------------------------------------------------------ +EmProtIns proc near + + test ES:[PrefixFlag],P0F_FLAG + jnz EmPI1 + jmp Not_ProtIns1 +EmPI1: + push dx + push ax + push es + mov dx, ES:[PrefixFlag] + mov bx,VDMCA_GSEL ; Load CODE (writeable) alias + mov es, bx + assume es:_TEXT + inc si ; set si past the opcode + mov bl,[si] ; BL = modR/M + mov bh, bl ; BH = modR/M + and bl, 38h + cmp bl, 30h + je EmLMSW ; Emulate LMSW + cmp bl, 18h + jne LGDTerr ; VM guy not allowed to LGDT + mov bx, ErrLIDT + jmp ExitPIer ; VM guy not allowed to LIDT +LGDTerr: + mov bx, ErrLGDT + jmp ExitPIer +EmLMSW: + inc si ; set SI past the modR/M + mov [bp.VTFOE+VMTF_EIP],si ; VM CS:IP = DS:SI + mov bl, bh ; BL = modR/M + cmp bl, 0C0h ; is MSW being loaded from a register? + jb MoveData ; N: do a move from the VM's memory + jmp MoveReg ; Y: go do a register move + +MoveData: +; Because of all the possible addressing modes this is pretty nasty. Like +; MoveReg, it is complicated by the requirement to not clear the PE bit. +; The general approach is to find the client's data value, put it in AX, +; set the PE bit in AX, then load the MSW from AX. To keep from having +; to know about all the modR/M combinations, we yank the client's possible +; offset from his code, and put his slightly modified modR/M byte in our +; home-made MOV AX, MemData instruction. + +; If there is a data offset, yank it from the VM instruction and put it +; in our instruction. + + and bl, 0C7h ; Force AX to be the MOV destination + mov byte ptr es:[LMSWmod],bl + mov ax, 09090h + mov word ptr es:[LMSWoff],ax ; initialize offset to NOPS + cmp bl, 06h ; special case for DS:d16 + je load16off + and bl, 0C0h + cmp bl, 040h + je load8off + cmp bl, 080h + jne BldDesc ; No data offset, so go build desc +Load16off: + mov ax,[si] ; AX = 16 bit offset + mov word ptr es:[LMSWoff],ax + add si, 2 + mov [bp.VTFOE+VMTF_EIP],si ; VM CS:IP = DS:SI + jmp short BldDesc +Load8off: + mov al,[si] ; AL = 8 bit offset + mov byte ptr es:[LMSWoff],al + inc si + mov [bp.VTFOE+VMTF_EIP],si ; VM CS:IP = DS:SI + +BldDesc: +; Build a descriptor to the client's data segment + + mov bl, bh + mov ax, [bp.VTFOE+VMTF_DS] ; Assume DS is the data segment + +; Check for segment override + and dx, 00FCh ; strip all but segment overrides + cmp dx, CS_FLAG + jl GetmodBase ; no override, check base + je CS_data + cmp dx, ES_FLAG + je ES_data + jl GetSel ; ds is override + cmp dx, FS_FLAG + jl SS_data + je FS_data +GS_data: + mov ax, [bp.VTFOE+VMTF_GS] ; GS is the data segment + jmp short GetSel +FS_data: + mov ax, [bp.VTFOE+VMTF_FS] ; FS is the data segment + jmp short GetSel +SS_data: + mov ax, VM1_GSEL + mov ds, ax + jmp short RestoreRegs +CS_data: + mov ax, VM2_GSEL + mov ds, ax + jmp short RestoreRegs +ES_data: + mov ax, [bp.VTFOE+VMTF_ES] ; ES is the data segment + jmp short GetSel + +GetmodBase: +; We have no Segment override, so we need to look at the modR/M byte to +; see whether or not the data index/offset is based on DS (assumed) or SS + and bl, 0C7h ; clear instruction bits + cmp bl, 46h + je SS_Data ; EA = SS:[BP+d8] + and bl, 7 + cmp bl, 2 + je SS_Data ; EA = SS:[BP+SI+?] + cmp bl, 3 + je SS_Data ; EA = SS:[BP+DI+?] + +GetSel: +; Build a selector (VM2_GSEL) to client's data. VM2_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; The Descriptor base VM segment value is in AX + push es + push bx + mov bx,GDTD_GSEL ; get GDT data alias + mov es,bx ; DS -> GDT + mov bx, ax ; copy the VM data segment value + shl ax,4 ; BX = low 16 bits of base + mov es:[VM2_GSEL+2],ax ; place in descriptor + shr bx,4 ; BH = high 8 bits of base + mov es:[VM2_GSEL+4],bh ; place in descriptor + mov ax, VM2_GSEL + mov ds, ax + pop bx + pop es + +RestoreRegs: +; Since BX, SI, DI, and BP can all be used to form an effective address we +; blindly restore BX, SI, and BP from the stack so that we don't +; have to know what the instruction is using for its effective address. +; DI does not need to be restored, because it should still be the client's + + push bp + mov bp, sp + +; Now the Stack had better look like PROT_INS_FRAME. (vm386.inc) + mov si, [bp.PIF_ESI] + mov bx, [bp.PIF_EBX] + mov bp, [bp.PIF_EBP] + +; Move the VM data operand to AX + db 3Eh ; ds overide (for bp & di) + db 8Bh ; MOV opcode +LMSWmod db 00h ; modR/M +LMSWoff db 90h, 90h ; possible offset (NOPS otherwise) + + jmp ExLMSW ; Finally... go do the LMSW + +MoveReg: +; Here we have a LMSW from one of the general registers. This is pretty +; ugly because many of the possible registers the client might have used +; are currently saved on the stack. It is also complicated by the +; requirement to not clear the PE bit. The general approach is to find +; the client's register value/image, put it in AX, set the PE bit in AX, +; then load the MSW from AX. To keep from having to know all the modR/M +; combinations, we again use a slightly modified client's modR/M byte in +; our home-made MOV AX, RegData instruction. + + push bp + mov bp, sp + +; Now the Stack had better look like PROT_INS_FRAME. (vm386.inc) + + and bh, 07h ; If Src is AX, it hasn't been changed + jz ExLMSW ; so just go do the the LMSW +CkSrcBX: ; otherwise, find it and move it to AX + cmp bh, 3 + jne CkSrcBP + mov ax, [bp.PIF_EBX] ; src was BX, get from stack + jmp short ExLMSW +CkSrcBP: + cmp bh, 5 + jne CkSrcSI + mov ax, [bp.PIF_EBP] ; src was BP, get from stack + jmp short ExLMSW +CkSrcSI: + cmp bh, 6 + jne CkSrcDX + mov ax, [bp.PIF_ESI] ; src was SI, get from stack + jmp short ExLMSW +CkSrcDX: + cmp bh, 2 + jne CkSrcSP + mov ax, [bp.PIF_DX] ; src was DX, get from stack + jmp short ExLMSW +CkSrcSP: + cmp bh, 4 + jne GetReg + mov ax, [bp.PIF_VMESP] ; src was SP, get from stack + jmp short ExLMSW +GetReg: + or bh, 0C0h ; set register to register move bits + mov es:[Lmod], bh ; setup move from client's src register + jmp short GetRn ; clear prefetch so that bh gets there +GetRn: +; Execute MOV AX, Rn + db 08Bh +Lmod db 0C0h + +; Finally Execute the LMSW +ExLMSW: + +; At this point we could check for the PE bit and notify the user that +; he must switch to real mode... but because an old app might do a SMSW, +; which copies the PE bit (?!!), then set a bit in that image and do a LMSW, +; (not caring about the PE bit), we just let it go... under the assumption +; that if he really were trying to enter Protected mode, he would have +; failed trying to LIDT and LGDT. + +; test ax, 0001h ; Is client trying to set PE bit +; jnz ExitPIer ; Y: jump to error + or ax, 0001h ; N: we want to stay in Prot mode + LMSW ax ; So we must set it (use BTS above) + + pop bp + pop es + assume es:DGROUP + pop ax + pop dx + jmp EmExit ; *** RETURN *** to VM client + +ExitPIer: + pop es + assume es:DGROUP + mov ax, PrivErr ; privileged error + call ErrHndlr ; If the user want's to continue + pop ax + pop dx + jmp JumpReal ; we return and go unwind the stack +Not_ProtIns1: + jmp BadVmTrap + +EmProtIns endp + +;****************************************************************************** +; EmMovCDTR - emulate the - MOV Rn, C/D/TRn & MOV C/D/TRn, Rn - instructions +; This is done by copying the MOV instruction from the VM to our +; code and then executing it. If CR0 is being stored, the PE +; bit is masked clear before completing the instruction. Execution speed +; should not be critical for these instructions, so I have lumped them +; all together to save memory that can be better used for more time +; critical emulations. +; NOTE: The Stack configuration is critical!!! If it is changed, the +; offsets to the register images must be updated accordingly. +; +; Also NOTE: The TR register opcodes have been removed from the legal 0F +; prefix list, (P0F_OpTab(x)), and the EmMovCDTR address removed from their +; opcode table ,(OpTable), vectors, so that they don't come here anymore. +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting opcode = nn (DS = VM2_GSEL) +; EXIT: via IRET to VM client +; bp.VTFOE+VMTF_EIP points beyond offender to next client instruction +; USED: +; STACK: n/a +;------------------------------------------------------------------------------ +EmMovCDTR proc near + + test ES:[PrefixFlag],P0F_FLAG + jnz MovCDTR1 + jmp Not_MovCDTR ; Didn't come from a 0F prefix +MovCDTR1: + PUSH_EAX + push es + mov bx,VDMCA_GSEL ; Load CODE (writeable) alias + mov es, bx + assume es:_TEXT + mov bl,[si] ; BL = opcode + mov es:[CDTRopc], bl + inc si ; set SI past the opcode + mov bl,[si] ; BL = modR/M + mov bh, bl ; Copy modR/M + and bl, 0F8h ; For control, we reroute move thru AX + mov es:[CDTRmod], bl + inc si ; set SI past the modR/M + mov [bp.VTFOE+VMTF_EIP],si ; VM CS:IP = DS:SI + + push bp + mov bp, sp + +; Now the Stack had better look like MOV_CDTR_FRAME. (vm386.inc) + + mov bl, es:[CDTRopc] ; load opcode + cmp bl, 024h ; Check TRn load/store + jb NotTRErr ; N: continue + mov bx, ErrMovTR ; Y: go flag error + jmp CTRErr + +NotTRErr: + and bh, 7 ; strip all but src reg bits + cmp bh, 0 + je ExCDTR ; reg is AX, so just do move + + cmp bl, 020h ; Check CRn store + je ExCDTR1 ; Y: go do it + cmp bl, 021h ; Check DRn store + je ExCDTR1 ; Y: go do it + +ChkSrcBX: + cmp bh, 3 + jne ChkSrcBP + OP32 + mov ax, [bp.MCF_EBX] ; mov EBX from stack + jmp short ExCDTR +ChkSrcBP: + cmp bh, 5 + jne ChkSrcSI + OP32 + mov ax, [bp.MCF_EBP] ; mov EBP from stack + jmp short ExCDTR +ChkSrcSI: + cmp bh, 6 + jne ChkSrcSP + OP32 + mov ax, [bp.MCF_ESI] ; mov ESI from stack + jmp short ExCDTR +ChkSrcSP: + cmp bh, 4 + jne GetFmReg + OP32 + mov ax, [bp.MCF_VMESP] ; mov ESP from stack + jmp short ExCDTR +GetFmReg: + or bh, 0C0h ; set register to register move bits + mov es:[CDTRreg], bh ; setup move from client's src register + jmp short GetERn ; clear prefetch so that bh gets there +GetERn: +; Execute MOV EAX, ERn + OP32 + db 08Bh +CDTRreg db 0C0h + +ExCDTR: + cmp bl, 022h ; Check CRn load + jne FltrDRL3 ; N: destination not CRn + cmp byte ptr es:[CDTRmod], 0C0h ; Check for CR0 load + je CR0FltrL ; Y: filter it + mov bx, ErrMovCR + jmp CTRErr ; N: go tell user he did a NoNo +FltrDRL3: + cmp byte ptr es:[CDTRmod], 0C3h ; Check for DR0-3 load + ja FltrGDbit ; N: continue + call MapLinear ; Y: convert address to our paging + jmp short ExCDTR1 ; linear map, then continue +FltrGDbit: + cmp byte ptr es:[CDTRmod], 0C7h ; Check for DR7 load + jne ExCDTR1 ; N: continue + and ax, 0DFFFh ; Y: don't let client set the GD bit + jmp short ExCDTR1 ; continue + +; For the reason below, we don't bug the user about setting the PE bit +; through LMSW. To be consistent, and because the client would die +; in his attmept to LGDT or Mov CR3,Reg before this, we let him go here +; also. +; LMSW Reason: +; At this point we could check for the PE bit and notify the user that +; he must switch to real mode... but because an old app might do a SMSW, +; which copies the PE bit (?!!), then set a bit in that image and do a LMSW, +; (not caring about the PE bit), we just let it go... under the assumption +; that if he really were trying to enter Protected mode, he would have +; failed trying to LIDT and LGDT. + +CR0FltrL: +; OP32 +; test AX, 0FFFEh ; Is Client trying to set the +; dw 7FFFh ; PE bit or the PG bit? +; jnz ExitxCRer ; Y: go tell him he can't + OP32 + or AX, 0001h ; set PE bit + dw 8000h ; and PG bit if they weren't +ExCDTR1: +; Execute MOV CDTRn, EAX (Finally!) + db 0Fh +CDTRopc db 020h +CDTRmod db 0C0h + +; The special register move has now been executed, but we altered it to +; use AX. If the move was a load, we are done. If it was a store to one of +; the registers on the stack, we need to stuff the register's stack image, +; otherwise we need to move AX to the proper register. + + cmp bl, 022h ; Check CRn load + je Exit_MovCDTR ; Y: we're done + cmp bl, 023h ; Check DRn load + je Exit_MovCDTR ; Y: we're done + cmp bl, 021h ; Check DRn store + je FltrDRS3 ; Y: go filter it + jmp short NotDRS3 +FltrDRS3: + cmp byte ptr es:[CDTRmod], 0C3h ; Check for DR0-3 load + ja NotDRS3 ; N: continue + call UnMapLinear ; Y: convert address from our paging + ; linear map, then continue +NotDRS3: + cmp bl, 020h ; Check CRn store + jne ChkDstBX ; N: source not CRn + cmp byte ptr es:[CDTRmod], 0C0h ; Check for CR0 store + je CR0FltrS ; Y: filter it + mov bx, ErrMovCR + jmp short CTRErr ; N: go tell user he did a NoNo + +; Because SMSW shows the PE bit, we let it go through here also +CR0FltrS: + OP32 + and AX, 0FFFFh ; Y: clear + dw 7FFFh ; PG bit if it was set +ChkDstBX: + cmp bh, 3 + jne ChkDstBP + OP32 + mov [bp.MCF_EBX], ax ; mov EBX to stack + jmp short Exit_MovCDTR +ChkDstBP: + cmp bh, 5 + jne ChkDstSI + OP32 + mov [bp.MCF_EBP], ax ; mov EBP to stack + jmp short Exit_MovCDTR +ChkDstSI: + cmp bh, 6 + jne ChkDstAX + OP32 + mov [bp.MCF_ESI], ax ; mov ESI to stack + jmp short Exit_MovCDTR +ChkDstAX: + cmp bh, 0 + jne ChkDstSP + OP32 + mov [bp.MCF_EAX], ax ; mov EAX to stack + jmp short Exit_MovCDTR ; at exit +ChkDstSP: + cmp bh, 4 + jne PutInReg + OP32 + mov [bp.MCF_VMESP], ax ; mov ESP to stack + jmp short Exit_MovCDTR ; at exit +PutInReg: +; Execute MOV ERn, EAX + or bh, 0C0h ; set register to register move bits + mov es:[regCDTR], bh ; setup load to client's dest register + jmp short PutERn ; clear prefetch so that bh gets there +PutERn: + db 66h + db 089h +regCDTR db 0C0h + + +Exit_MovCDTR: + pop bp + pop es + assume es:DGROUP + POP_EAX + jmp EmExit ; *** RETURN *** to VM client +CTRErr: + mov ax, PrivErr + pop bp + sub [bp.VTFOE+VMTF_EIP],3 ; VM CS:IP = faulting instruction + pop es + assume es:DGROUP + call ErrHndlr ; If we return here, the user wants to + POP_EAX ; continue in real mode... so go unwind + jmp JumpReal ; the stack and let him continue +Not_MovCDTR: + jmp BadVmTrap + +EmMovCDTR endp + +;****************************************************************************** +;*** EmLOCK - Emulate LOCK prefix +; +; This routine is entered if a faulting instruction +; is a LOCK prefix. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; +EmLOCK proc near + +; 6/15 - Probably should jump to VmInsHandle rather than EmExit to handle a +; a lock prefix on some other offending instruction. In that case you would +; have: +;; or ES:[PrefixFlag],LOCK_FLAG ; set appropriate flag +;; inc si ; inc VM CS:IP past prefix +;; jmp VmInsHandle ; and go process offender +; rather than: + inc si ; set IP past the + mov [bp.VTFOE+VMTF_EIP], si ; instruction we emulate + jmp EmExit ; and leave + +EmLOCK endp + +;****************************************************************************** +;*** EmREPNE - handle REPNE prefix +; +; We come here if the trapping instruction has +; a REPNE prefix. We just pass it on to the handler +; for the next opcode. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +EmREPNE proc near + + or ES:[PrefixFlag],REPNE_FLAG ; set appropriate flag + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +EmREPNE endp + +;*** EmREP - handle REP prefix +; +; We come here if the trapping instruction has +; a REP or REPE prefix. We just pass it on to the handler +; for the next opcode. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +EmREP proc near + + or ES:[PrefixFlag],REP_FLAG ; set appropriate flag + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +EmREP endp + +;****************************************************************************** +;*** Prefix_0F - handle 0F overrides +; +; This routine is entered if an instruction begins with a 0F prefix. +; It checks the current opcode against a table of valid 0F-opcodes, +; and if the opcode is valid, it indexes back into OpTable to jump +; to the proper opcode handler. +; (NOTE: This scheme works fine as long as the valid 0F-opcodes +; continue to have low values allowing this P0F_OpTabx to stay +; relatively small. If this changes, we probably should go back +; to using the P0F_OpTab scheme.) +; +; ENTRY: 386 Protected Mode +; EBP,EBX,ESI pushed on stack +; VM1_GSEL = VM client's stack segment +; VM2_GSEL = VM client's code segment +; DS:SI -> faulting prefix = nn (DS = VM2_GSEL) +; EXIT xfer directly to handler for next opcode +; +;*** +P0F_Invalid equ 0FFh ; OpTable vector offset to BadVmTrap + +P0F_OpTabx label byte + db 00h ; 00h - LLDT, LTR, SLDT, STR, VERR, VERW + db 02h ; 01h - LIDT, LGDT, LMSW + db 04h ; 02h - LAR + db 06h ; 03h - LSL + db P0F_Invalid ; 04h - BadVmTrap + db 0Ah ; 05h - 286 Loadall + db 0Ch ; 06h - CLTS + db 0Eh ; 07h - 386 Loadall + db P0F_Invalid ; 08h - BadVmTrap + db P0F_Invalid ; 09h - BadVmTrap + db P0F_Invalid ; 0Ah - BadVmTrap + db P0F_Invalid ; 0Bh - BadVmTrap + db P0F_Invalid ; 0Ch - BadVmTrap + db P0F_Invalid ; 0Dh - BadVmTrap + db P0F_Invalid ; 0Eh - BadVmTrap + db P0F_Invalid ; 0Fh - BadVmTrap + db P0F_Invalid ; 10h - BadVmTrap + db P0F_Invalid ; 11h - BadVmTrap + db P0F_Invalid ; 12h - BadVmTrap + db P0F_Invalid ; 13h - BadVmTrap + db P0F_Invalid ; 14h - BadVmTrap + db P0F_Invalid ; 15h - BadVmTrap + db P0F_Invalid ; 16h - BadVmTrap + db P0F_Invalid ; 17h - BadVmTrap + db P0F_Invalid ; 18h - BadVmTrap + db P0F_Invalid ; 19h - BadVmTrap + db P0F_Invalid ; 1Ah - BadVmTrap + db P0F_Invalid ; 1Bh - BadVmTrap + db P0F_Invalid ; 1Ch - BadVmTrap + db P0F_Invalid ; 1Dh - BadVmTrap + db P0F_Invalid ; 1Eh - BadVmTrap + db P0F_Invalid ; 1Fh - BadVmTrap + db 40h ; 20h - CR moves + db 42h ; 21h - DR moves + db 44h ; 22h - CR moves + db 46h ; 23h - DR moves + db 48h ; 24h - TR moves + db P0F_Invalid ; 25h - BadVmTrap + db 4Ch ; 26h - TR moves +P0F_OpTabx_Size equ $-P0F_OpTabx + +;*** +Prefix_0F proc near + inc si ; inc DS:SI past prefix + mov bl,[si] ; BL = opcode + cmp bl, P0F_OpTabx_Size + jae Bad_0F + mov bh,0 ; BX = opcode + mov bl, cs:P0F_OpTabx[bx] + cmp bl, P0F_Invalid + je Bad_0F + or es:[PrefixFlag],P0F_FLAG ; set appropriate flag + jmp cs:OpTable[bx] ; enter instr emulation routine + +Bad_0F: + jmp BadVmTrap + +Prefix_0F endp + +;****************************************************************************** +;*** CSOverride - handle CS overrides +; +; This routine is entered if a faulting instruction +; has a CS override. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; +CSOverride proc near + + or ES:[PrefixFlag],CS_FLAG ; set appropriate flag + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +CSOverride endp + +;****************************************************************************** +;*** DSOverride - handle DS overrides +; +; This routine is entered if a faulting instruction +; has a DS override. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; +DSOverride proc near + + or ES:[PrefixFlag],DS_FLAG ; set appropriate flag + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +DSOverride endp + +;****************************************************************************** +;*** ESOverride - handle ES overrides +; +; This routine is entered if a faulting instruction +; has a ES override or a MOV TRn, Rn opcode +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; + +ESOverride proc near + + test ES:[PrefixFlag],P0F_FLAG ; only for TR emulation + jz ESO1 ; only for TR emulation + jmp EmMovCDTR ; only for TR emulation +ESO1: + or ES:[PrefixFlag],ES_FLAG ; set appropriate flag + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +ESOverride endp + +;****************************************************************************** +;*** SSOverride - handle SS overrides +; +; This routine is entered if a faulting instruction +; has a SS override. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; + +SSOverride proc near + + or ES:[PrefixFlag],SS_FLAG ; set appropriate flag +;; inc [bp.VTFOE+VMTF_EIP] ; inc VM CS:IP past prefix + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +SSOverride endp + +;****************************************************************************** +;*** FSOverride - handle FS overrides +; +; This routine is entered if a faulting instruction +; has a FS override. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; + +FSOverride proc near + + or ES:[PrefixFlag],FS_FLAG ; set appropriate flag +;; inc [bp.VTFOE+VMTF_EIP] ; inc VM CS:IP past prefix + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +FSOverride endp + +;****************************************************************************** +;*** GSOverride - handle GS overrides +; +; This routine is entered if a faulting instruction +; has a GS override. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT xfer on to handler for next opcode +; + +GSOverride proc near + + or ES:[PrefixFlag],GS_FLAG ; set appropriate flag +;; inc [bp.VTFOE+VMTF_EIP] ; inc VM CS:IP past prefix + inc si ; inc VM CS:IP past prefix + jmp VmInsHandle ; handle next part of instr + +GSOverride endp + +;****************************************************************************** +;*** EmINSB - emulate IN byte string +; +; This routine emulates the IN byte string instruction +; *** this routine emulates REP instructions entirely *** +; *** within protected mode. This effectively masks out *** +; *** interupts between bytes in the operation, even *** +; *** if the VM code had interrupts on. *** +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +; USES ES,BX,DI +; + +EmINSB proc near +; +;; inc [bp.VTFOE+VMTF_EIP] ; set IP past the instruction we emulate + inc si ; set IP past the + mov [bp.VTFOE+VMTF_EIP], si ; instruction we emulate +; +; +; Build a selector (VM1_GSEL) to client's ES segment. VM1_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; + mov bx,GDTD_GSEL + mov ds,bx ; DS = GDT selector + mov bx,[bp.VTFOE+VMTF_ES] ; BX = VM ES (segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFOE+VMTF_ES] ; BX = VM ES (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM1_GSEL+4],bh ; place in descriptor + mov bx,VM1_GSEL + test ES:[PrefixFlag],REP_FLAG ;Q: REP prefix active ? + mov es,bx ; ES = VM ES + jnz EINSB_loop ; Y: go do rep instruction + insb ; N: do single instruction + jmp EINSB_exit ; and leave +EINSB_loop: + cld ; assume cld + mov bx,DF_FLAG + test bx,word ptr [bp.VTFOE+VMTF_EFLAGS] ;Q: client's DF bit is CLD? + jz EINSB_rep ; Y: go ahead + std ; N: set it +EINSB_rep: + rep insb ; rep version + +EINSB_Exit: ; + jmp EmExit ; *** RETURN *** to VM client +; +EmINSB endp + + +;****************************************************************************** +;*** EmINSW - emulate IN word string +; +; This routine emulates the IN word string instruction +; *** this routine emulates REP instructions entirely *** +; *** within protected mode. This effectively masks out *** +; *** interupts between bytes in the operation, even *** +; *** if the VM code had interrupts on. *** +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +; USES ES,BX,DI +; + +EmINSW proc near +; +;; inc [bp.VTFOE+VMTF_EIP] ; set IP past the instruction we emulate + inc si ; set IP past the + mov [bp.VTFOE+VMTF_EIP], si ; instruction we emulate +; +; +; +; Build a selector (VM1_GSEL) to client's ES segment. VM1_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; + mov bx,GDTD_GSEL + mov ds,bx ; DS = GDT selector + mov bx,[bp.VTFOE+VMTF_ES] ; BX = VM ES (segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFOE+VMTF_ES] ; BX = VM ES (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM1_GSEL+4],bh ; place in descriptor + mov bx,VM1_GSEL + test ES:[PrefixFlag],REP_FLAG ;Q: REP prefix active ? + mov es,bx ; ES = VM ES + jnz EINSW_loop ; Y: go do rep instruction + insw ; N: do single instruction + jmp EINSW_exit ; and leave +EINSW_loop: + cld ; assume cld + mov bx,DF_FLAG + test bx,word ptr [bp.VTFOE+VMTF_EFLAGS] ;Q: client's DF bit is CLD? + jz EINSW_rep ; Y: go ahead + std ; N: set it +EINSW_rep: + rep insw ; rep version + +EINSW_Exit: ; + jmp EmExit ; *** RETURN *** to VM client +; +EmINSW endp + + +;****************************************************************************** +;*** EmOUTSB - emulate OUT byte string +; +; This routine emulates the OUT byte string instruction +; *** this routine emulates REP instructions entirely *** +; *** within protected mode. This effectively masks out *** +; *** interupts between bytes in the operation, even *** +; *** if the VM code had interrupts on. *** +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +; USES DS,BX,SI +; + +EmOUTSB proc near +; +;; inc [bp.VTFOE+VMTF_EIP] ; set IP past the instruction we emulate + inc si ; set IP past the + mov [bp.VTFOE+VMTF_EIP], si ; instruction we emulate +; +; restore SI +; + pop si + push si +; +; Build a selector (VM1_GSEL) to client's DS segment. VM1_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; + mov bx,GDTD_GSEL + mov ds,bx ; DS = GDT selector + mov bx,[bp.VTFOE+VMTF_DS] ; BX = VM DS (segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFOE+VMTF_DS] ; BX = VM DS (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM1_GSEL+4],bh ; place in descriptor + mov bx,VM1_GSEL + mov ds,bx ; DS = VM DS + + test ES:[PrefixFlag],REP_FLAG ;Q: REP prefix active ? + jnz EOUTSB_loop ; Y: go do rep instruction + outsb ; N: do single instruction + jmp EOUTSB_exit ; and leave +EOUTSB_loop: + cld ; assume cld + mov bx,DF_FLAG + test bx,word ptr [bp.VTFOE+VMTF_EFLAGS] ;Q: client's DF bit is CLD? + jz EOUTSB_rep ; Y: go ahead + std ; N: set it +EOUTSB_rep: + rep outsb ; rep version + +EOUTSB_Exit: ; + jmp EmExit ; *** RETURN *** to VM client +; +EmOUTSB endp + + +;****************************************************************************** +;*** EmOUTSW - emulate OUT word string +; +; This routine emulates the OUT word string instruction +; *** this routine emulates REP instructions entirely *** +; *** within protected mode. This effectively masks out *** +; *** interupts between bytes in the operation, even *** +; *** if the VM code had interrupts on. *** +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +; USES DS,BX,SI +; + +EmOUTSW proc near +; +;; inc [bp.VTFOE+VMTF_EIP] ; set IP past the instruction we emulate + inc si ; set IP past the + mov [bp.VTFOE+VMTF_EIP], si ; instruction we emulate +; +; restore SI +; + pop si + push si +; +; +; Build a selector (VM1_GSEL) to client's DS segment. VM1_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; + mov bx,GDTD_GSEL + mov ds,bx ; DS = GDT selector + mov bx,[bp.VTFOE+VMTF_DS] ; BX = VM DS (segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFOE+VMTF_DS] ; BX = VM DS (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM1_GSEL+4],bh ; place in descriptor + mov bx,VM1_GSEL + mov ds,bx ; DS = VM DS + + test ES:[PrefixFlag],REP_FLAG ;Q: REP prefix active ? + jnz EOUTSW_loop ; Y: go do rep instruction + outsw ; N: do single instruction + jmp EOUTSW_exit ; and leave +EOUTSW_loop: + cld ; assume cld + mov bx,DF_FLAG + test bx,word ptr [bp.VTFOE+VMTF_EFLAGS] ;Q: client's DF bit is CLD? + jz EOUTSW_rep ; Y: go ahead + std ; N: set it +EOUTSW_rep: + rep outsw ; rep version + +EOUTSW_Exit: ; + jmp EmExit ; *** RETURN *** to VM client +; +EmOUTSW endp + +;****************************************************************************** +;*** EmMOVSW - emulate MOV word string +; +; This routine emulates the MOV word string instruction +; specifically to handle the RASH Rules (Jokes) emulation. +; For now, the only reason for doing this is to allow a bug +; in PC Week's benchmark tests to FAIL "properly" so that the test +; works. (Unbelievable!) +; +; NOTE: After testing, if the ROM properly emulates the RASH +; requirements, this routine should be reduced to the Reflect6 +; function. +; +; ENTRY 386 PROTECTED MODE +; see common description at top +; +; EXIT IRET back to VM program +; +; USES DS,BX,SI +; +EmMOVSW proc near + mov bx, sp + cmp di, 0FFFFh ; Q:Does either Di + je EmWRASH + cmp ss:[bx.GPF_ESI], 0FFFFh ; or SI = FFFF? + je EmWRASH ; Y:Assume RASH GPfault +Reflect6: + mov es:[RefNum], 06h +RefToROM: + POP_ESI ; N: clean up the stack, + POP_EBX + POP_EBP + add sp,4 ; throw away error code, + PUSH_EBP + mov bp,sp ; reset BP to stack frame + push es:[RefNum] ; push the trap number + jmp hw_int ; and, Reflect to ROM +EmWRASH: + test es:[PrefixFlag], REPS_FLAG ; Q:Is this a REP of REPNE? + jz EMWCXok ; N: don't change CX + inc cx +EMWCXok: + mov ax, 2 ; assume up counter + test [bp.VTFOE+VMTF_EFLAGS], DF_FLAG + jz EMWUpdtSI + not ax +EMWUpdtSI: + mov si, ss:[bx.GPF_ESI] + add ss:[bx.GPF_ESI], ax ; verify neg??? + cmp si, 0FFFFh ; Q:Did SI cause the GP fault + jne EMWUpdtDI ; N:Go fixup DI and CX + jmp short EMW_Exit ; Y:We're done +EMWUpdtDI: + test es:[PrefixFlag], REPS_FLAG ; Q:Is this a REP of REPNE? + jz EMWCXok2 ; N: don't change CX + inc cx +EMWCXok2: + add di, ax ; verify neg??? +EMW_Exit: + jmp EmExit ; *** RETURN *** to VM client +; +EmMOVSW endp + +_TEXT ends + + end + diff --git a/v4.0/src/MEMM/MEMM/VMTRAP.ASM b/v4.0/src/MEMM/MEMM/VMTRAP.ASM new file mode 100644 index 0000000..095ebef --- /dev/null +++ b/v4.0/src/MEMM/MEMM/VMTRAP.ASM @@ -0,0 +1,791 @@ + + +page 58,132 +;****************************************************************************** + title VMTRAP - 386 Virtual Mode interrupt handler routines +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver +; +; Module: VMTRAP - 386 Virtual Mode interrupt handler routines +; +; Version: 0.02 +; +; Date: January 26, 1986 +; +; Author: +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------ +; 01/26/86 Original +; 02/05/86 A- Added int 15h trap to move block function. +; 05/12/86 A Cleanup and segment reorganization +; 06/19/86 0.01 Added emul_reflect entry point for preserving +; IF and TF flags bits on reflections done by +; instruction emulators. +; 06/28/86 0.02 Name change from MEMM386 to MEMM +; 07/20/88 Removed debugger codes (pc) +; +;****************************************************************************** +; +; Functional Description: +; +; This module contains the interrupt and trap handlers for Virtual DOS. +; +; Note that a conscious decision has been made to attempt to field the +; Master 8259 interrupts at the normal PC location (vectors 8 - F). The +; main problem is that these overlap CPU exception vectors. While the +; 8259 base vector address could be changed (there's lots of room in the +; IDT, since we're fielding S/W INTs through GP 13), the primary reason +; for not doing so is to avoid any potential trouble with an application +; reprogramming the 8259. We don't know of any that do, and you could +; trap them if they tried anyway. +; +; "to do:" marks potential holes/things to consider +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + page +;****************************************************************************** +; P U B L I C D E C L A R A T I O N S +;****************************************************************************** +; + public VmTrap ; module label + + public hw_int + public emul_reflect + + public vm_trap00 + public vm_trap01 + public vm_trap02 + public vm_trap03 + public vm_trap04 + public vm_trap05 + public vm_trap06 + public vm_trap07 + public vm_trap08 + public vm_trap09 + public vm_trap0a + public vm_trap0b + public vm_trap0c + public vm_trap0d + public vm_trap0e + public vm_trap0f + public vm_trap10 + public vm_trap50 + public vm_trap51 + public vm_trap52 + public vm_trap53 + public vm_trap54 + public vm_trap55 + public vm_trap56 + public vm_trap57 + public vm_trap70 + public vm_trap71 + public vm_trap72 + public vm_trap73 + public vm_trap74 + public vm_trap75 + public vm_trap76 + public vm_trap77 + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** +; +_TEXT segment + extrn VmFault:near ; V Mode GP fault handler (VMINST) + extrn ErrHndlr:near ; Error Handler (ERRHNDLR) + extrn DisableNMI:near ; Disable NMI for NMI trap handler +_TEXT ends + page +;****************************************************************************** +; I N C L U D E F I L E S +;****************************************************************************** +; +include VDMseg.inc +include VDMsel.inc +include vm386.inc +include pic_def.equ +include instr386.inc +include oemdep.inc + + page +;****************************************************************************** +; L O C A L C O N S T A N T S +;****************************************************************************** +; +FALSE equ 0 +TRUE equ not FALSE + +ProcessExcep macro ExcepNum + mov bx, ExcepNum + mov ax, ExcpErr + jmp ErrHndlr +endm +; +;****************************************************************************** +; S E G M E N T D E F I N I T I O N +;****************************************************************************** +; +ABS0 segment at 0000h +ABS0 ends +; +;------------------------------------------------------------------------------ +_TEXT segment + assume cs:_TEXT, ds:NOTHING, es:NOTHING, ss:NOTHING +VmTrap label byte +; + db 'WCC' +; + page +;****************************************************************************** +; CPU: Divide error fault +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap00 proc near + PUSH_EBP + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmt0_dexit ; N: exit to debugger + push 0000 ; Y: interrupt 00 + jmp hw_int ; reflect it to virtual mode +vmt0_dexit: + ProcessExcep ErrDIV +vm_trap00 endp + +;****************************************************************************** +; CPU: Debug trap +; +; Traps from Virtual mode are reflected to virtual mode. Unfortunately +; this breaks the debugger's ability to GO and TRACE the VM program. +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap01 proc near + PUSH_EBP + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmt1_dexit ; N: exit to debugger + push 0001 ; Y: interrupt 01 + jmp hw_int ; reflect it to virtual mode +vmt1_dexit: + ProcessExcep ErrINT1 +vm_trap01 endp + +;****************************************************************************** +; H/W: NMI +; +; For now, this always traps to the debugger. It's a general purpose hook +; to let the debugger get control via an NMI button. +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap02 proc near + PUSH_EBP + mov bp,sp + + call DisableNMI + + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmt2_parity ; N: error/debug trap + ; Y: reflect it/debugger + push 02 ; reflect it + jmp hw_int +vmt2_parity: + ProcessExcep ErrNMI + +vm_trap02 endp + +;****************************************************************************** +; CPU: Breakpoint trap (INT 3 instruction) +; +; Traps from Virtual mode are reflected to virtual mode. Unfortunately +; this breaks the debugger's ability to GO and TRACE the VM program. +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap03 proc near + ProcessExcep ErrINT3 +vm_trap03 endp + +;****************************************************************************** +; CPU: Overflow trap (INTO instruction) +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap04 proc near + ProcessExcep ErrINTO +vm_trap04 endp + + +;****************************************************************************** +; CPU: Array bounds fault +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap05 proc near + PUSH_EBP + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmt5_dexit ; N: exit to debugger + push 0005 ; Y: interrupt 01 + jmp hw_int ; reflect it to virtual mode +vmt5_dexit: + ProcessExcep ErrBounds +vm_trap05 endp + +;****************************************************************************** +; CPU: Invalid Opcode fault +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +; +; add Invalid instruction emulator ??? (specifically LOCK prefix) +; +;------------------------------------------------------------------------------ +vm_trap06 proc near + push 0 ; align stack with error offset + push 0 ; for VmFault + PUSH_EBP + mov bp,sp + test [bp.VTFOE+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmt6_dexit ; N: exit to debugger + jmp VmFault ; Y: enter VM 06 Invalid handler + +vmt6_dexit: + ProcessExcep ErrOpCode +vm_trap06 endp + +;****************************************************************************** +; CPU: Coprocessor not present fault +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap07 proc near + PUSH_EBP + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmt7_dexit ; N: exit to debugger + push 0007 ; Y: interrupt 07 + jmp hw_int ; reflect it to virtual mode +vmt7_dexit: + ProcessExcep ErrCoPNA +vm_trap07 endp + + +;****************************************************************************** +; CPU: Double Fault +; H/W: IRQ0 - System timer +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; Error Code on stack = 0000 +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap08 proc near + PUSH_EBP + mov bp,sp + cmp sp,VMT_STACK ; Q: H/W interrupt from VM ? + jne vmt8_dexit ; N: exit to debugger + push 0008 ; Y: interrupt 8 + jmp hw_int ; reflect it to virtual mode +vmt8_dexit: + ProcessExcep ErrDouble +vm_trap08 endp + + +;****************************************************************************** +; CPU: (none for 386) +; H/W: IRQ1 - Keyboard +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap09 proc near + PUSH_EBP + mov bp,sp + push 0009 ; Y: interrupt 9 + jmp hw_int ; reflect it to virtual mode +vm_trap09 endp + +;****************************************************************************** +; CPU: Invalid TSS fault +; H/W: IRQ2 - Cascade from slave 8259 (see INT 70-77) +; (shouldn't get H/W interrupts here) +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; Error Code on stack = Selector +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: + +; to do: someone could reprogram master 8259 - need to handle ? +;------------------------------------------------------------------------------ +vm_trap0A proc near + ProcessExcep ErrTSS +vm_trap0A endp + + +;****************************************************************************** +; CPU: Segment Not Present fault +; H/W: IRQ3 - COM2 +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; Error Code on stack = Selector +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap0B proc near + PUSH_EBP + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmtB_dexit ; N: exit to debugger + push 000Bh ; Y: interrupt 0B + jmp hw_int ; reflect it to virtual mode +vmtB_dexit: + ProcessExcep ErrSegNP +vm_trap0B endp + +;****************************************************************************** +; CPU: Stack fault +; H/W: IRQ4 - COM1 +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; Error Code on stack = Selector or 0000 +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap0C proc near + PUSH_EBP + mov bp,sp + test [bp.VTFO+VMTF_EFLAGShi],2 ; Q: client in Virtual Mode ? + jz vmtC_dexit ; N: exit to debugger + push 000Ch ; Y: interrupt 0C + jmp hw_int ; reflect it to virtual mode +vmtC_dexit: + ProcessExcep ErrStack +vm_trap0C endp + +;****************************************************************************** +; CPU: General Protection fault +; H/W: IRQ5 - Second parallel printer +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; Error Code on stack = Selector or 0000 +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap0D proc near + PUSH_EBP + mov bp,sp + cmp sp,VMT_STACK ; Q: H/W interrupt from VM ? + jne vmtD_1 ; N: continue + push 000Dh ; Y: interrupt vector 0Dh + jmp hw_int ; reflect it to virtual mode +; +; Here we have a GP fault that was not a H/W interrupt 13 from VM. +; +vmtD_1: + cmp sp,VMTERR_STACK ; Q: 'normal' exception w/error code ? + jne vmtD_dexit ; N: what the hell was it ???? - exit + jmp VmFault ; Y: enter VM GP fault handler + ; (fall thru to debugger) +vmtD_dexit: + ProcessExcep ErrGP +vm_trap0D endp + +;****************************************************************************** +; CPU: Page fault +; H/W: IRQ6 - diskette interrupt +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; Error Code on stack = type of fault +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap0E proc near + PUSH_EBP + mov bp,sp + cmp sp,VMT_STACK ; Q: H/W interrupt from VM ? + jne vmtE_dexit ; N: exit to debugger + push 000Eh ; Y: interrupt vector 0Eh + jmp hw_int ; reflect it to virtual mode +vmtE_dexit: + ProcessExcep ErrPage +vm_trap0E endp + +;****************************************************************************** +; CPU: (none) +; H/W: IRQ7 - parallel printer +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap0F proc near + PUSH_EBP + mov bp,sp + push 000Fh ; push interrupt number + jmp hw_int ; enter common H/W interrupt handler +vm_trap0F endp + +;****************************************************************************** +; CPU: Coprocessor Error - GOES TO NOT PRESENT FAULT IN DEBUGGER FOR NOW +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; No error code on stack +; EXIT: to handler or debugger as appropriate +; USED: +; STACK: +;------------------------------------------------------------------------------ +vm_trap10 proc near + ProcessExcep ErrCoPerr +vm_trap10 endp + +;****************************************************************************** +; VmTrap5x - Handlers for hardware interrupts. Sometimes the master 8259 +; is set to here. +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; EXIT: EBP pushed on stack +; BP = normal stack frame pointer +; Interrupt number pushed on stack +; USED: +; STACK: (4 bytes) +;------------------------------------------------------------------------------ +vm_trap50 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0050h + jmp short hw_int ; enter common code +vm_trap50 endp + +;------------------------------------------------------------------------------ +vm_trap51 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0051h + jmp short hw_int ; enter common code +vm_trap51 endp + +;------------------------------------------------------------------------------ +vm_trap52 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0052h + jmp short hw_int ; enter common code +vm_trap52 endp + +;------------------------------------------------------------------------------ +vm_trap53 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0053h + jmp short hw_int ; enter common code +vm_trap53 endp + +;------------------------------------------------------------------------------ +vm_trap54 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0054h + jmp short hw_int ; enter common code +vm_trap54 endp + +;------------------------------------------------------------------------------ +vm_trap55 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0055h + jmp short hw_int ; enter common code +vm_trap55 endp + +;------------------------------------------------------------------------------ +vm_trap56 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0056h + jmp short hw_int ; enter common code +vm_trap56 endp + +;------------------------------------------------------------------------------ +vm_trap57 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0057h + jmp short hw_int ; enter common code +vm_trap57 endp + +;****************************************************************************** +; VmTrap7x - handlers for hardware interrupts from the slave 8259 +; +; ENTRY: 386 Protected Mode via 386 Interrupt gate +; EXIT: EBP pushed on stack +; BP = normal stack frame pointer +; Interrupt number pushed on stack +; USED: +; STACK: (4 bytes) +;------------------------------------------------------------------------------ +vm_trap70 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0070h + jmp short hw_int ; enter common code +vm_trap70 endp + +;------------------------------------------------------------------------------ +vm_trap71 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0071h + jmp short hw_int ; enter common code +vm_trap71 endp + +;------------------------------------------------------------------------------ +vm_trap72 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0072h + jmp short hw_int ; enter common code +vm_trap72 endp + +;------------------------------------------------------------------------------ +vm_trap73 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0073h + jmp short hw_int ; enter common code +vm_trap73 endp + +;------------------------------------------------------------------------------ +vm_trap74 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0074h + jmp short hw_int ; enter common code +vm_trap74 endp + +;------------------------------------------------------------------------------ +vm_trap75 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0075h + jmp short hw_int ; enter common code +vm_trap75 endp + +;------------------------------------------------------------------------------ +vm_trap76 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0076h + jmp short hw_int ; enter common code +vm_trap76 endp + +;------------------------------------------------------------------------------ +vm_trap77 proc near + PUSH_EBP + mov bp,sp ; set up BP frame pointer + push 0077h + jmp short hw_int ; enter common code +vm_trap77 endp + + page +;****************************************************************************** +; HW_INT - common handler for hardware interrupts. The interrupt is +; reflected directly to the appropriate Real Mode (Virtual) handler. +; This entry point clear the trace flag (TF) and int flag (IF), since +; a h/w interrupt would (NOTE: INT n and INTO instructions also clear +; TF and IF - so this entry is suitable for reflecting these also). +; +; EMUL_REFLECT - entry point for reflecting emulations. +; This entry point does not clear the trace flag (TF) and int flag (IF). +; +; 386 interrupt gate switched us to the Ring 0 stack on the way in +; from Virtual Mode and pushed 32-bit values as follows: +; +; hiword loword offset (in addition to EBP push) +; +------+------+ <-------- Top of 'kernel' stack +; | 0000 | GS | +32 (decimal) +; |------|------| +; | 0000 | FS | +28 +; |------|------| +; | 0000 | DS | +24 +; |------|------| +; | 0000 | ES | +20 +; |------|------| +; | 0000 | SS | +16 +; |------|------| +; | ESP | +12 +; |------|------| +; | EFLAGS | +08 +; |------|------| +; | 0000 | CS | +04 +; |------|------| +; | EIP | +00 +; +------+------+ <-------- Ring 0 SS:SP +; | (ebp) | +; +-------------+ <-------- Ring 0 SS:BP +; +; The object of this routine is to massage the trap stack frame (above) +; and build a 'real mode' stack frame for the virtual mode client so that +; we can transfer control to virtual mode at the address specified in +; the appropriate real mode IDT vector. The client's IRET out of the +; interrupt routine will proceed normally (assuming we're letting him +; run with IOPL = 3). Since we're fielding the trap from Virtual Mode, +; we assume the high word of ESP and EIP is 0000. +; +; +-------+ <-------- Client's current SS:SP +; | Flags | +4 +; |-------| +; | CS | +2 +; |-------| +; | IP | +0 +; +-------+ <-------- Client's SS:SP when we let him have control +; +; Assume entry from Virtual Mode, for now. We shouldn't be getting entered +; here except via Hardware interrupt, so no sanity checks are performed. +; +; ENTRY: 386 Protected Mode +; BP -> standard frame +; EBP and Interrupt number have been pushed onto stack +; EXIT: via IRET to VM86 program +; appropriate real mode IRET set up @ client's SS:SP +; USED: (none) (note that DS & ES are free to use - saved during trap) +; STACK: +; +; to do: Need to check for entry mode ? +;------------------------------------------------------------------------------ +hw_int proc near + push bx + push si ; + mov si,[bp.VTFO+VMTF_EFLAGS] ; SI = saved low word of EFLAGS +; +; *** clear IF bit and Trace Flag on flags for reflect, but leave them +; unchanged for the flags on the IRET stack we build on the +; client's stack. +; + and [bp.VTFO+VMTF_EFLAGS],not 300h ; clear IF and TF +reflect_common: +; +; Build a selector (VM1_GSEL) to client's stack. VM1_GSEL is already set +; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base. +; + HwTabUnlock ; disable HW protection on high ram + mov bx,GDTD_GSEL ; get GDT data alias + mov ds,bx ; DS -> GDT + mov bx,[bp.VTFO+VMTF_SS] ; BX = VM SS (segment form) + shl bx,4 ; BX = low 16 bits of base + mov ds:[VM1_GSEL+2],bx ; place in descriptor + mov bx,[bp.VTFO+VMTF_SS] ; BX = VM SS (again) + shr bx,4 ; BH = high 8 bits of base + mov ds:[VM1_GSEL+4],bh ; place in descriptor +; +; Adjust client's SP to make room for building his IRET frame +; + sub word ptr [bp.VTFO+VMTF_ESP],6 ; adjust client's SP + mov bx, VM1_GSEL + mov ds, bx ; DS = VM stack segment +; + mov bx,si ; BX = low word of client's EFLAGS +; + mov si,[bp.VTFO+VMTF_ESP] ; DS:SI = pointer to client's frame +; +; Move low 16 bits of Flags, CS, and EIP from IRET frame to client stack frame +; + mov ds:[si.4],bx ; to client's flags + mov bx,[bp.VTFO+VMTF_CS] ; + mov ds:[si.2],bx ; to client's CS + mov bx,[bp.VTFO+VMTF_EIP] ; low word of EIP + mov ds:[si.0],bx ; to client's IP +; +; Replace low 16 bits of IRET frame CS:EIP with vector from real mode IDT +; + mov bx,[bp-2] ; get the interrupt vector + shl bx,2 ; BX = BX * 4 (vector table index) + mov si,RM_IDT_GSEL ; get real mode IDT alias + mov ds,si ; DS -> Real Mode IDT + mov si,ds:[bx] ; + mov [bp.VTFO+VMTF_EIP],si ; move the IP + mov si,ds:[bx+2] ; + mov [bp.VTFO+VMTF_CS],si ; move the CS +; +; 32-bit IRET back to client +; + HwTabLock ; enable HW protection on high ram + pop si ; restore local regs + pop bx + pop bp ; throw away fake interrupt number + POP_EBP + db 66h + iret ; *** RETURN *** to client +hw_int endp + +;****************************************************************************** +; EMUL_REFLECT +;****************************************************************************** +; +; emulation relfection entry point - don't mess with client's flags +; +emul_reflect label near + push bx ; local registers + push si ; + mov si,[bp.VTFO+VMTF_EFLAGS] ; SI = saved low word of EFLAGS + jmp reflect_common + + +; +_TEXT ends ; end of segment +; + end ; end of module + \ No newline at end of file -- cgit v1.2.3