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/EMMP.ASM | 2978 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2978 insertions(+) create mode 100644 v4.0/src/MEMM/EMM/EMMP.ASM (limited to 'v4.0/src/MEMM/EMM/EMMP.ASM') 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 -- cgit v1.2.3