//++
// Copyright (c) 2006 - 2008, 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:
//    FlushCacheRange.s 
//
//  Abstract:
//    Assemble routine to flush cache lines 
//
// Revision History:
//
//--
.file  "IpfCpuCache.s"

#include <IpfMacro.i>

//
//  Invalidates a range of instruction cache lines in the cache coherency domain
//  of the calling CPU.
//
//  Invalidates the instruction cache lines specified by Address and Length. If
//  Address is not aligned on a cache line boundary, then entire instruction
//  cache line containing Address is invalidated. If Address + Length is not
//  aligned on a cache line boundary, then the entire instruction cache line
//  containing Address + Length -1 is invalidated. This function may choose to
//  invalidate the entire instruction cache if that is more efficient than
//  invalidating the specified range. If Length is 0, the no instruction cache
//  lines are invalidated. Address is returned.
//  This function is only available on IPF.
//
//  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
//
//  @param  Address The base address of the instruction cache lines to
//                  invalidate. If the CPU is in a physical addressing mode, then
//                  Address is a physical address. If the CPU is in a virtual
//                  addressing mode, then Address is a virtual address.
//
//  @param  Length  The number of bytes to invalidate from the instruction cache.
//
//  @return Address
//  
//  VOID *
//  EFIAPI
//  AsmFlushCacheRange (
//    IN      VOID                      *Address,
//    IN      UINTN                     Length
//    );
//
PROCEDURE_ENTRY (AsmFlushCacheRange)

      NESTED_SETUP (5,8,0,0)
            
      mov         loc2 = ar.lc
      
      mov         loc3 = in0                  // Start address.
      mov         loc4 = in1;;                // Length in bytes.
      
      cmp.eq  p6,p7 = loc4, r0;;               // If Length is zero then don't flush any cache
      (p6)  br.spnt.many DoneFlushingC;;         
      
      add         loc4 = loc4,loc3 
      mov         loc5 = 1;;
      sub         loc4 = loc4, loc5 ;; // the End address to flush
                                         
      dep         loc3 = r0,loc3,0,5          
      dep         loc4 = r0,loc4,0,5;;         
      shr         loc3 = loc3,5             
      shr         loc4 = loc4,5;;    // 32 byte cache line
      
      sub         loc4 = loc4,loc3;; // total flush count, It should be add 1 but 
                                     // the br.cloop will first execute one time 
      mov         loc3 = in0                  
      mov         loc5 = 32      
      mov         ar.lc = loc4;;

StillFlushingC:
      fc          loc3;; 
      sync.i;;
      srlz.i;;
      add         loc3 = loc5,loc3;;
      br.cloop.sptk.few StillFlushingC;;

DoneFlushingC:      
      mov         ar.lc = loc2     
      mov          r8   = in0       // return *Address
      NESTED_RETURN

PROCEDURE_EXIT (AsmFlushCacheRange)

