;/*++
;
;Copyright (c) 2006, Intel Corporation                                                         
;All rights reserved. This program and the accompanying materials                          
;are licensed and made available under the terms and conditions of the BSD License         
;which accompanies this distribution.  The full text of the license may be found at        
;http://opensource.org/licenses/bsd-license.php                                            
;                                                                                          
;THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
;WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
;
;Module Name:
;
;  EfiZeroMem.c
;
;Abstract:
;
;  This is the code that supports IA32-optimized ZeroMem service
;
;--*/
;---------------------------------------------------------------------------
    .686
    .model  flat,C
    .mmx
    .code

;---------------------------------------------------------------------------
;VOID
;EfiCommonLibZeroMem (
;  IN VOID   *Buffer,
;  IN UINTN  Count
;  )
;/*++
;
;Input:  VOID   *Buffer - Pointer to buffer to clear
;        UINTN  Count  - Number of bytes to clear
;
;Output: None.
;
;Saves:
;
;Modifies:
;
;Description:  This function is an optimized zero-memory function.
;
;Notes:  This function tries to zero memory 8 bytes at a time. As a result, 
;        it first picks up any misaligned bytes, then words, before getting 
;        in the main loop that does the 8-byte clears.
;
;--*/
EfiCommonLibZeroMem PROC
;  UINT64 MmxSave;
    push  ebp
    mov   ebp, esp
    push  ecx  ; Reserve space for local variable MmxSave
    push  ecx
    push  edi
    
    mov   ecx, [ebp + 0Ch] ; Count
    mov   edi, [ebp + 8]; Buffer

    ; Pick up misaligned start bytes (get pointer 4-byte aligned)
_StartByteZero:
    mov   eax, edi    
    and   al, 3                       ; check lower 2 bits of address
    test  al, al
    je    _ZeroBlocks                 ; already aligned?
    cmp   ecx, 0
    je    _ZeroMemDone

    ; Clear the byte memory location
    mov   BYTE PTR [edi], 0           
    inc    edi

    ; Decrement our count
    dec    ecx
    jmp   _StartByteZero        ; back to top of loop

_ZeroBlocks:

    ; Compute how many 64-byte blocks we can clear 
    mov   edx, ecx
    shr   ecx, 6                      ; convert to 64-byte count
    shl   ecx, 6                      ; convert back to bytes
    sub   edx, ecx                    ; subtract from the original count
    shr   ecx, 6                      ; and this is how many 64-byte blocks

    ; If no 64-byte blocks, then skip 
    cmp    ecx, 0
    je    _ZeroRemaining

    ; Save mm0
    movq  [ebp - 8], mm0  ; Save mm0 to MmxSave

    pxor  mm0, mm0          ; Clear mm0

_B:
    movq  QWORD PTR ds:[edi], mm0
    movq  QWORD PTR ds:[edi+8], mm0
    movq  QWORD PTR ds:[edi+16], mm0
    movq  QWORD PTR ds:[edi+24], mm0
    movq  QWORD PTR ds:[edi+32], mm0
    movq  QWORD PTR ds:[edi+40], mm0
    movq  QWORD PTR ds:[edi+48], mm0
    movq  QWORD PTR ds:[edi+56], mm0
   
    add    edi, 64
    dec    ecx
    jnz    _B
  
; Restore mm0
    movq  mm0, [ebp - 8] ; Restore mm0 from MmxSave
    emms                                 ; Exit MMX Instruction

_ZeroRemaining:
    ; Zero out as many DWORDS as possible
    mov   ecx, edx
    shr   ecx, 2
    xor   eax, eax

    rep stosd

    ; Zero out remaining as bytes
    mov   ecx, edx
    and   ecx, 03

    rep   stosb
 
_ZeroMemDone:

    pop    edi
    leave
    ret
EfiCommonLibZeroMem ENDP	
	END
