Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

438 lines
13 KiB
ArmAsm

# @(#)58 1.1.1.3 src/bos/kernel/ml/POWER/cache_ppc.s, sysml, bos411, 9428A410j 5/31/94 10:25:24
#*****************************************************************************
#
# COMPONENT_NAME: (SYSML) Kernel Assembler Code
#
# FUNCTIONS: sync_cache_page_ppc, vm_cflush_ppc_comb,
# vm_cflush_ppc_splt, inval_icache_page_ppc
#
# ORIGINS: 27
#
# IBM CONFIDENTIAL -- (IBM Confidential Restricted when
# combined with the aggregated modules for this product)
# SOURCE MATERIALS
# (C) COPYRIGHT International Business Machines Corp. 1993
# All Rights Reserved
#
# US Government Users Restricted Rights - Use, duplication or
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
#
#***************************************************************************
.file "cache_ppc.s"
#***************************************************************************
#
# INCLUDED FUNCTIONS:
# sync_cache_page_ppc
# vm_cflush_ppc_comb
# vm_cflush_ppc_splt
# inval_icache_page_ppc
#
# N.B: sync_cache_range_ppc is in lib/c/sys/sync_cache.s
#
#***************************************************************************
#***************************************************************************
#
# NAME: sync_cache_page_ppc
#
# FUNCTION: synchronize I cache with D cache for a page
#
# sync_cache_page_ppc(raddr) rc = none
#
# INPUT STATE:
# r3 = real starting address of the page
#
# OUTPUT STATE:
# Caches for the specified page are synchronized
#
# EXECUTION ENVIRONMENT:
# called with I/D translation off
#
# Note: This implementation assumes that I/D cache line size is
# a power of two and is less than or equal to 1/4 of the page size.
# It handles/optimizes for combined cache case.
#***************************************************************************
.machine "ppc"
S_PROLOG(sync_cache_page_ppc)
LTOC(r5,_system_configuration,data)
# check parameters and cache attribute
cal r9,PSIZE/4(0) # r9 = number of bytes to flush/4
l r4,scfg_cattrib(r5) # get cache attribute
l r6,scfg_dcb(r5) # r6 = dcache_blk_size
andil. r4,r4,0x0002 # cr0 equal bit = 1 if split cache
l r7,scfg_icb(r5) # r7 = icache_blk_size,
cntlz r8,r6
beq cr0,sync_page_ppc_spl # branch if split I/D cache
# combined I/D cache
sfi r8,r8,31 # r8 = log2(cache_blk_size)
sr r10,r9,r8 # r10 = loop count
sf r5,r6,r3 # subtract blk size to start loop
mtctr r10 # set up loop counter
sync_loop:
dcbst r5,r6 # store one cache blk
a r5,r5,r6 # go to the next blk
dcbst r5,r6
a r5,r5,r6
dcbst r5,r6
a r5,r5,r6
dcbst r5,r6
a r5,r5,r6
bdn sync_loop # dec ctr and branch if non-zero
sync # wait until memory updated
isync
br
# split I/D cache
sync_page_ppc_spl:
sfi r8,r8,31 # r8 = log2(dcache_blk_size)
cntlz r4,r7
sr r10,r9,r8 # r10 = loop count
sfi r4,r4,31 # r4 = log2(icache_blk_size)
sf r5,r6,r3 # subtract blk size to start loop
mtctr r10 # set up loop counter
sync_dloop:
dcbst r5,r6 # store one dcache blk
a r5,r5,r6 # go to the next blk
dcbst r5,r6
a r5,r5,r6
dcbst r5,r6
a r5,r5,r6
dcbst r5,r6
a r5,r5,r6
bdn sync_dloop # dec ctr and branch if non-zero
# start icache invalidation
sr r10,r9,r4 # r10 = loop count
sf r5,r7,r3 # subtract blk size to start loop
mtctr r10 # set up loop counter
sync # wait until memory updated
sync_iloop:
icbi r5,r7 # invalidate one icache blk
a r5,r5,r7 # go to the next blk
icbi r5,r7
a r5,r5,r7
icbi r5,r7
a r5,r5,r7
icbi r5,r7
a r5,r5,r7
bdn sync_iloop # dec ctr and branch if non-zero
ifdef(`_POWER_MP',`
sync # wait until icbis are globally performed
',)
isync # wait until icbi completes and discard
# prefetched instructions
S_EPILOG
#***************************************************************************
#
# NAME: vm_cflush_ppc_comb
#
# FUNCTION: flush I cache and D cache for a memory range
#
# vm_cflush_ppc_comb (eaddr, nbytes)
#
# INPUT STATE:
# r3 = starting effective address to flush
# r4 = byte count
#
# OUTPUT STATE:
# Caches with data in the specified range are flushed
#
# RETURN VALUE:
# 0 if success
# EINVAL if nbytes < 0
#
# EXECUTION ENVIRONMENT:
# Called through the branch table
#
#***************************************************************************
.machine "ppc"
S_PROLOG(vm_cflush_ppc_comb)
# r5 = address of _system_configuration structure
# r6 = value of cache-block-size field in the structure
LTOC(r5,_system_configuration,data)
cmpi cr0,r4,0 # see if nbytes is le 0
l r6,scfg_dcb(r5) # r6 = cache block size,
ble cr0,spec0_nbytes # branch if nbytes <= 0
ai r7,r6,-1 # get mask of log2(cache block size) length
# -- this assumes cache block size is
# a power of two.
cntlz r11,r6
# num_cache_blocks =
# (offset_into_cache_block + nbytes + cache_block_size - 1) /
# cache_block_size
and r8,r7,r3 # mask off offset in cache block
sfi r11,r11,31 # r11 = log2(cache block size)
a r8,r8,r4 # offset + nbytes
sf r5,r6,r3 # subtract block size to start loop
a r9,r8,r7 # + cache block size - 1
sr r10,r9,r11 # / cache block size
sri r8,r10,2 # r8 = bigloop count
andil. r9,r10,0x3 # r9 = # blocks to flush in com_remainloop
cmpi cr1,r8,0 # chech if big loop count is 0
beq ppc_com_bigloop # if nothing left for remainloop
mtctr r9 # setup loop count
ppc_com_remainloop:
dcbf r5,r6 # flush a cache block
a r5,r5,r6 # increment r5 to the next cache block
bdn ppc_com_remainloop # dec ctr and branch if non-zero
ppc_com_bigloop:
beq cr1,ppc_com_sync
mtctr r8 # setup loop count
ppc_com_bigloop1:
dcbf r5,r6 # flush a cache block
a r5,r5,r6 # increment r5 to the next cache block
dcbf r5,r6
a r5,r5,r6
dcbf r5,r6
a r5,r5,r6
dcbf r5,r6
a r5,r5,r6
bdn ppc_com_bigloop1 # dec ctr and branch if non-zero
ppc_com_sync:
lil r3,0x0 # success return code
sync # wait for memory updates to complete
isync # discard prefretched instructions
br
spec0_nbytes:
lil r3,0x0 # success return code
beqr cr0 # return if nbytes = 0
lil r3,EINVAL # error return code
S_EPILOG
FCNDES(vm_cflush_ppc_comb)
#***************************************************************************
#
# NAME: vm_cflush_ppc_splt
#
# FUNCTION: flush I cache and D cache for a memory range
#
# vm_cflush_ppc_splt(eaddr, nbytes)
#
# INPUT STATE:
# r3 = starting effective address to flush
# r4 = byte count
#
# OUTPUT STATE:
# Caches with data in the specified range are flushed
#
# RETURN VALUE:
# 0 if success
# EINVAL if nbytes < 0
#
# EXECUTION ENVIRONMENT:
# Called through the branch table
#
#***************************************************************************
.machine "ppc"
S_PROLOG(vm_cflush_ppc_splt)
# r5 = address of _system_configuration structure
# r6 = value of dcache-block-size field in the structure
LTOC(r5,_system_configuration,data)
cmpi cr0,r4,0 # see if nbytes is le 0
l r6,scfg_dcb(r5) # r6 = dcache block size,
ble cr0,spec1_nbytes # branch if nbytes <= 0
l r12,scfg_icb(r5) # r12 = icache block size
ai r7,r6,-1 # get mask of log2(dcache block size) length
# --this assumes cache block size is
# a power of two.
cntlz r11,r6
# num_cache_blocks =
# (offset_into_cache_block + nbytes + cache_block_size - 1) /
# cache_block_size
and r8,r7,r3 # mask off offset in cache block
sfi r11,r11,31 # r11 = log2(dcache block size)
a r8,r8,r7 # offset + cache block size - 1
sf r5,r6,r3 # subtract block size to start loop
a r9,r8,r4 # + nbytes
ai r7,r12,-1 # get mask of log2(icache block size) length
# -- this assumes cache block size is
# a power of two.
sr r10,r9,r11 # / cache block size
cntlz r11,r12
sri r8,r10,2 # r8 = bigloop count
andil. r9,r10,0x3 # r9 = # blocks to flush in d_remainloop
cmpi cr1,r8,0 # chech if big loop count is 0
beq ppc_d_bigloop # if nothing left for remainloop
mtctr r9 # setup loop count
ppc_d_remainloop:
dcbf r5,r6 # flush a dcache block
a r5,r5,r6 # increment r4 to the next cache block
bdn ppc_d_remainloop # dec ctr and branch if non-zero
ppc_d_bigloop:
and r10,r7,r3 # mask off offset in cache block
sfi r11,r11,31 # r11 = log2(icache block size)
a r10,r10,r4 # offset + nbytes
beq cr1,ppc_d_sync
mtctr r8 # setup loop count
ppc_d_bigloop1:
dcbf r5,r6 # flush a dcache block
a r5,r5,r6 # increment r5 to the next cache block
dcbf r5,r6
a r5,r5,r6
dcbf r5,r6
a r5,r5,r6
dcbf r5,r6
a r5,r5,r6
bdn ppc_d_bigloop1 # dec ctr and branch if non-zero
ppc_d_sync:
a r9,r10,r7 # + cache block size - 1
sync # wait for memory updates to complete
# num_cache_blocks =
# (offset_into_cache_block + nbytes + cache_block_size - 1) /
# cache_block_size
sr r8,r9,r11 # / cache block size
sf r5,r12,r3 # subtract block size to start loop
sri r10,r8,2 # r8 = bigloop count
andil. r9,r8,0x3 # r9 = # blocks to flush in i_remainloop
cmpi cr1,r10,0 # chech if big loop count is 0
beq ppc_i_bigloop # if nothing left for remainloop
mtctr r9 # setup loop count
ppc_i_remainloop:
icbi r5,r12 # flush a icache block
a r5,r5,r12 # increment r5 to the next cache block
bdn ppc_i_remainloop # dec ctr and branch if non-zero
ppc_i_bigloop:
beq cr1,ppc_i_sync
mtctr r10 # setup loop count
ppc_i_bigloop1:
icbi r5,r12 # flush a icache block
a r5,r5,r12 # increment r5 to the next cache block
icbi r5,r12
a r5,r5,r12
icbi r5,r12
a r5,r5,r12
icbi r5,r12
a r5,r5,r12
bdn ppc_i_bigloop1 # dec ctr and branch if non-zero
ppc_i_sync:
lil r3,0x0 # success return code
isync # discard prefretched instructions
br
spec1_nbytes:
lil r3,0x0 # success return code
beqr cr0 # return if nbytes = 0
lil r3,EINVAL # error return code
S_EPILOG
FCNDES(vm_cflush_ppc_splt)
#***************************************************************************
#
# NAME: inval_icache_page_ppc
#
# FUNCTION: invalidate I cache for a page
#
# inval_icache_page_ppc(raddr) rc = none
#
# INPUT STATE:
# r3 = real starting address for the page
#
# OUTPUT STATE:
# icache for the specified page is invalidated
#
# Note: this implementation assumes that I cache line size is
# a power of two and is less than or equal to 1/4 of the page size.
#***************************************************************************
.machine "ppc"
S_PROLOG(inval_icache_page_ppc)
LTOC(r5,_system_configuration,data)
cal r9,PSIZE/4(0) # r9 = number of bytes to flush/4
l r4,scfg_cattrib(r5) # get cache attribute
l r6,scfg_icb(r5) # r6 = icache_blk_size
andil. r4,r4,0x0002 # cr0 equal bit = 1 if split cache
cntlz r7,r6
sfi r8,r7,31 # r8 = log2(icache_blk_size)
beq cr0,inval_icache # branch if split I/D cache
# UP && combined I/D cache
ifdef(`_POWER_MP',`
',`
isync
br
')
# MP or split I/D cache
inval_icache:
sr r10,r9,r8 # r10 = loop count
sf r11,r6,r3 # subtract blk size to start loop
mtctr r10 # set up loop counter
inv_icache_loop:
icbi r11,r6 # invalidate icache blk
a r11,r11,r6 # go to the next blk
icbi r11,r6
a r11,r11,r6
icbi r11,r6
a r11,r11,r6
icbi r11,r6
a r11,r11,r6
bdn inv_icache_loop # loop if not done
ifdef(`_POWER_MP',`
sync # wait until icache blks are globally
# invalidated
',)
isync # wait until icbi completes and discard
# prefetched instructions
S_EPILOG
.toc
TOCE(_system_configuration,data)
include(vmdefs.m4)
include(errno.m4)
include(systemcfg.m4)