#/*++
#
#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
#
#--*/
#include "EfiBind.h"
#---------------------------------------------------------------------------
    .686: 
    #.MODEL flat,C
    .mmx: 
    .code: 

#---------------------------------------------------------------------------
.globl ASM_PFX(EfiCommonLibZeroMem)
#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.
#
#--*/
ASM_PFX(EfiCommonLibZeroMem):
#  UINT64 MmxSave;
    pushl %ebp
    movl  %esp, %ebp
    pushl %ecx # Reserve space for local variable MmxSave
    pushl %ecx
    pushl %edi

    movl  0xC(%ebp), %ecx  # Count
    movl  8(%ebp), %edi # Buffer

    # Pick up misaligned start bytes (get pointer 4-byte aligned)
_StartByteZero: 
    movl  %edi, %eax
    andb  $3, %al                     # check lower 2 bits of address
    testb %al, %al
    je    _ZeroBlocks                 # already aligned?
    cmpl  $0, %ecx
    je    _ZeroMemDone

    # Clear the byte memory location
    movb  $0, (%edi)
    incl   %edi

    # Decrement our count
    decl   %ecx
    jmp   _StartByteZero        # back to top of loop

_ZeroBlocks: 

    # Compute how many 64-byte blocks we can clear 
    movl  %ecx, %edx
    shrl  $6, %ecx                    # convert to 64-byte count
    shll  $6, %ecx                    # convert back to bytes
    subl  %ecx, %edx                  # subtract from the original count
    shrl  $6, %ecx                    # and this is how many 64-byte blocks

    # If no 64-byte blocks, then skip 
    cmpl   $0, %ecx
    je    _ZeroRemaining

    # Save mm0
    movq  %mm0, -8(%ebp)  # Save mm0 to MmxSave

    pxor  %mm0, %mm0        # Clear mm0

_B: 
    movq  %mm0, %ds:(%edi)
    movq  %mm0, %ds:8(%edi)
    movq  %mm0, %ds:16(%edi)
    movq  %mm0, %ds:24(%edi)
    movq  %mm0, %ds:32(%edi)
    movq  %mm0, %ds:40(%edi)
    movq  %mm0, %ds:48(%edi)
    movq  %mm0, %ds:56(%edi)

    addl   $64, %edi
    decl   %ecx
    jnz    _B

# Restore mm0
    movq  -8(%ebp), %mm0 # Restore mm0 from MmxSave
    emms                                 # Exit MMX Instruction

_ZeroRemaining: 
    # Zero out as many DWORDS as possible
    movl  %edx, %ecx
    shrl  $2, %ecx
    xorl  %eax, %eax

    rep
    stosl

    # Zero out remaining as bytes
    movl  %edx, %ecx
    andl  $03, %ecx

    rep
    stosb

_ZeroMemDone: 

    popl   %edi
    leave
    ret
#EfiCommonLibZeroMem ENDP

