; a fast MEMMOVE routine that uses the 80836 if present ; this function can replace the memmove routine supplied with ; Microsoft and Borland C runtime libraries (sample coded in ; (small model) ; ; Author: M. Steven Baker ; Date: January 19, 1989 ; Last Revision: January 31, 1989 ; ; added test to force word alignment of source ; PROCEDURE cputype ; ; find out if we have an 80386 CPU to use ; This routine can be used from the real or virtual ; 8086 mode only. Otherwise will likely cause a ; protection violation (PUSHF instruction is ; privileged) ; ; Based on COMPAQ DESKPRO 386/20 Technical Reference Guide ; (originally suggested by INTEL) ; ; Entry: none ; Exit: AX = CPU type ; 0086h if 8088/8086 ; 0286h if 80286 ; 0386h if 80386 ; Stack: 8 bytes ; .MODEL small .CODE public _cputype _cputype proc near pushf ;save the real flags register ; pop ax ;get register off stack push ax ;and save it again ; and ax,0fffh ;zero out bits 12-15 push ax popf ;try to put into flags pushf pop ax ;let's see what came out ;of flags and ax,0F000h ;mask off bits 12-15 cmp ax,0F000h ;were these bits all 1's je is_86 ;if so, it's an 8086 ; pop ax ;get flags register to AX push ax ;and save it again ; or ax,0F000h ;now try to set bits 12-15 push ax popf ;of the flags register pushf pop ax ;and see what came out and ax,0F000h ;are high bits set je is_286 ;if so, we have a 386 is_386: mov ax,0386h jmp short cpu_exit ; is_286: mov ax,0286h jmp short cpu_exit ; is_86: mov ax,86h ; cpu_exit: popf ;restore flags ret _cputype endp ; ; PROCEDURE memmove ; ; void * memmove(void *dest,const void *src,size_t count); ; returns *dest public _memmove _memmove proc near push bp mov bp,sp ;use BP to get variables mov dx,di ;save register variables mov bx,si ;into BX and DX mov ax,ds mov es,ax ;force ES to DS (small model mov di,[bp+4] ;get destination ptr mov si,[bp+6] ;and source ptr mov cx,[bp+8] ;and byte count ; mov ax,di ;memmove returns dest ptr jcxz mmov_ret ;if count=0, where done ; cmp di,si ;do we have possible overlap jb forward1 ;if not go do it ; je mmov_ret ;if dest=src, then do nothing mov ax,si ; add ax,cx ;find end point of source cmp di,ax ;do we overlap with dest ? mov ax,di ;memmove must return dest ptr jae forward ;no overlap ; add si,cx ;copy from end of string back add di,cx std ;set reverse direction dec si dec di ; test si,1 ;are we at least word aligned? jz back1 movsb ;get word aligned dec cx ; back1: shr cx,1 ;convert to words jnc back2 ;carry if odd count movsb back2: dec si ;set index for word dec di shr cx,1 patch_o1: jnc back4 movsw back4: sub di,2 sub si,2 db 66h ;operand size [refix patch_i1: rep movsw cld ;force forward direction mmov_ret: mov si,bx ;restore register variables mov di,dx pop bp ret forward1: test si,1 ;are we at least word aligned? jz forward movsb ;get word aligned dec cx forward: shr cx,1 ;byte count to words jnc forwd4 ;if no carry, then even count movsb forwd4: shr cx,1 ;word count to dwords patch_o2: db 66h ;operand size prefix rep movsw ;(rep movsd) move double words adc cx,cx ;if carry was odd rep movsw ;if CX<>0 movsw ; mov si,bx ;restore register variables mov di,dx pop bp ret _memmove endp public _cpupatch _cpupatch proc near call _cputype cmp ax,0386h jne patch_mmove ret ; patch_mmove: push ds ;save registers push es push si push di push cx ; mov ax,cs ;set DS=ES to CS mov ds,ax mov es,ax mov si,offset patch_i1 ;input patch mov di,offset patch_o1 mov cx,(offset forward- offset patch_i1) rep movsb ; mov si,offset patch_i1 mov di,offset patch_o2 mov cx,(offset forward - offset patch_i1) rep movsb ; pop cx pop di pop si pop es pop ds ret _cpupatch endp end