mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1804 lines
55 KiB
1804 lines
55 KiB
// TITLE("Cache Flush")
|
|
//++
|
|
//
|
|
// Copyright (c) 1991-1993 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// j4cache.s
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements the code necessary for cache operations on
|
|
// a MIPS R4000.
|
|
//
|
|
// Environment:
|
|
//
|
|
// Kernel mode only.
|
|
//
|
|
//--
|
|
|
|
#include "halmips.h"
|
|
|
|
//
|
|
// Define cache operations constants.
|
|
//
|
|
|
|
#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache)
|
|
#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache)
|
|
#define FLUSH_BASE 0xfffe0000 // flush base address
|
|
#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D))
|
|
#define ECACHE_PROTECTION_BITS ((1 << ENTRYLO_V) | (2 << ENTRYLO_C) | (1 << ENTRYLO_D))
|
|
#define ECACHE_CONTROL_PHYSICAL_BASE 0xD0000000
|
|
#define FLUSH_BASE_HACK FLUSH_BASE
|
|
#define PMP_CONTROL_VIRTUAL_BASE 0xFFFFC000
|
|
#define PMP_CONTROL_PHYSICAL_BASE 0xC0000000
|
|
#define GLOBAL_CTRL_ECE 0x00800080
|
|
|
|
|
|
SBTTL("Change Color Page")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalChangeColorPage (
|
|
// IN PVOID NewColor,
|
|
// IN PVOID OldColor,
|
|
// IN ULONG PageFrame
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function changes the color of a page if the old and new colors
|
|
// do not match.
|
|
//
|
|
// The algorithm used to change colors for a page is as follows:
|
|
//
|
|
// 1. Purge (hit/invalidate) the page from the instruction cache
|
|
// using the old color.
|
|
//
|
|
// 2. Purge (hit/invalidate) the page from the data cache using
|
|
// the old color.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// NewColor (a0) - Supplies the page aligned virtual address of the
|
|
// new color of the page to change.
|
|
//
|
|
// OldColor (a1) - Supplies the page aligned virtual address of the
|
|
// old color of the page to change.
|
|
//
|
|
// PageFrame (a2) - Supplies the page frame number of the page that
|
|
// is changed.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
.struct 0
|
|
.space 3 * 4 // fill
|
|
CpRa: .space 4 // saved return address
|
|
CpFrameLength: // length of stack frame
|
|
CpA0: .space 4 // (a0)
|
|
CpA1: .space 4 // (a1)
|
|
CpA2: .space 4 // (a2)
|
|
CpA3: .space 4 // (a3)
|
|
|
|
NESTED_ENTRY(HalChangeColorPage, CpFrameLength, zero)
|
|
|
|
subu sp,sp,CpFrameLength // allocate stack frame
|
|
sw ra,CpRa(sp) // save return address
|
|
|
|
PROLOGUE_END
|
|
|
|
and a0,a0,COLOR_BITS // isolate new color bits
|
|
and a1,a1,COLOR_BITS // isolate old color bits
|
|
beq a0,a1,10f // if eq, colors match
|
|
sw a1,CpA1(sp) // save old color bits
|
|
sw a2,CpA2(sp) // save page frame
|
|
|
|
//
|
|
// Purge the instruction cache using the old page color.
|
|
//
|
|
|
|
move a0,a1 // set color value
|
|
move a1,a2 // set page frame number
|
|
li a2,PAGE_SIZE // set length of purge
|
|
jal HalPurgeIcachePage // purge instruction cache page
|
|
|
|
//
|
|
// Flush the data cache using the old page color.
|
|
//
|
|
|
|
lw a0,CpA1(sp) // get old color bits
|
|
lw a1,CpA2(sp) // get page frame number
|
|
li a2,PAGE_SIZE // set length of purge
|
|
jal HalFlushDcachePage // purge data cache page
|
|
10: lw ra,CpRa(sp) // get return address
|
|
addu sp,sp,CpFrameLength // deallocate stack frame
|
|
j ra // return
|
|
|
|
.end HalChangeColorPage
|
|
|
|
SBTTL("Flush Data Cache Page")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalFlushDcachePage (
|
|
// IN PVOID Color,
|
|
// IN ULONG PageFrame,
|
|
// IN ULONG Length
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function flushes (hit/writeback/invalidate) up to a page of data
|
|
// from the data cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Color (a0) - Supplies the starting virtual address and color of the
|
|
// data that is flushed.
|
|
//
|
|
// PageFrame (a1) - Supplies the page frame number of the page that
|
|
// is flushed.
|
|
//
|
|
// Length (a2) - Supplies the length of the region in the page that is
|
|
// flushed.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
|
|
LEAF_ENTRY(HalFlushDcachePage)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeDcacheFlushCount // get address of dcache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result
|
|
|
|
#endif
|
|
|
|
//
|
|
// Determine if the ECache is
|
|
// present (active) which means
|
|
// it is enabled.
|
|
//
|
|
la t0,HalpPmpExternalCachePresent
|
|
lw t0,0(t0)
|
|
beq t0,zero, noECacheFlushDcachePage
|
|
|
|
DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
//
|
|
// Calculate the tlbapping values
|
|
// and determine which half of the
|
|
// tlb entry to use for the on-chip
|
|
// cache.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
|
|
and a0,a0,COLOR_MASK // isolate color and offset bits
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a0 // compute color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a0,a0,0x1000 // isolate TB entry index
|
|
beql zero,a0,11f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
11: mfc0 t3,wired // get TB entry index
|
|
lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
|
|
lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
|
|
bnel zero,v0,16f // if ne, second level cache present
|
|
move t4,v0 // set flush block size
|
|
|
|
16:
|
|
|
|
//
|
|
// Now calculate the tlb mapping values
|
|
// for the ECache invalidate space and
|
|
// use the other "unused" tlb entry.
|
|
//
|
|
li t6, (ECACHE_CONTROL_PHYSICAL_BASE >> 2)
|
|
li t7, ((ECACHE_CONTROL_PHYSICAL_BASE >> PAGE_SHIFT) << ENTRYLO_PFN)
|
|
or t6, t6, t7
|
|
li t7, (((512*1024)-1) >> PAGE_SHIFT)
|
|
and t7, a1, t7
|
|
sll t7, t7, ENTRYLO_PFN
|
|
or t6, t6, t7
|
|
li t7, ECACHE_PROTECTION_BITS
|
|
or t6, t6, t7
|
|
|
|
move a3, zero
|
|
beql t1, zero, 17f
|
|
move t1, t6
|
|
|
|
move t2, t6
|
|
addiu a3, a3, 1
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Now we actually do the mapping
|
|
// by directly writing the TLB
|
|
//
|
|
17:
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
subu t6,t4,1 // compute block size minus one
|
|
and t7,t0,t6 // compute offset in block
|
|
addu a2,a2,t6 // round up to next block
|
|
addu a2,a2,t7 //
|
|
nor t6,t6,zero // complement block size minus one
|
|
and a2,a2,t6 // truncate length to even number
|
|
beq zero,a2,31f // if eq, no blocks to flush
|
|
and t8,t0,t6 // compute starting virtual address
|
|
addu t9,t8,a2 // compute ending virtual address
|
|
subu t9,t9,t4 // compute ending loop address
|
|
|
|
//
|
|
// Now we use the mapped
|
|
// vaddr based on which half
|
|
// of the tlb entry we used
|
|
// for the ECache mapping.
|
|
//
|
|
move t6, t8
|
|
li t7, PAGE_SIZE
|
|
beql a3, zero, 21f
|
|
subu t6, t6, t7
|
|
|
|
addu t6, t6, t7
|
|
|
|
//
|
|
// Flush the primary data cache and
|
|
// invalidate the external cache.
|
|
//
|
|
21: cache HIT_WRITEBACK_INVALIDATE_D,0(t8) // invalidate cache block
|
|
nop
|
|
sw zero,0(t6) // ECache line invalidate
|
|
addu t6,t6,t4 // compute next address
|
|
bne t8,t9,21b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Now we will mark the ECache page
|
|
// invalid before exiting ...
|
|
//
|
|
31:
|
|
.set noreorder
|
|
.set noat
|
|
|
|
#if 1
|
|
|
|
//mtc0 zero, entrylo0
|
|
//mtc0 zero, entrylo1
|
|
//nop
|
|
|
|
#else
|
|
beq zero, a3, 22f
|
|
nop
|
|
|
|
mtc0 zero, entrylo1
|
|
b 23f
|
|
nop
|
|
|
|
22:
|
|
mtc0 zero, entrylo0
|
|
nop
|
|
|
|
23:
|
|
|
|
#endif
|
|
|
|
//nop
|
|
//nop
|
|
//nop
|
|
//tlbwi
|
|
//nop
|
|
//nop
|
|
//nop
|
|
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
//
|
|
// This section of code is only executed
|
|
// if the processor is not an R4600/R4700 or
|
|
// it is an R4600/R4700 but there is no ECache.
|
|
//
|
|
noECacheFlushDcachePage:
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
|
|
and a0,a0,COLOR_MASK // isolate color and offset bits
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a0 // compute color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a0,a0,0x1000 // isolate TB entry index
|
|
beql zero,a0,10f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
10: mfc0 t3,wired // get TB entry index
|
|
lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
|
|
lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
|
|
bnel zero,v0,15f // if ne, second level cache present
|
|
move t4,v0 // set flush block size
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Flush a page from the data cache.
|
|
//
|
|
|
|
15: DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
subu t6,t4,1 // compute block size minus one
|
|
and t7,t0,t6 // compute offset in block
|
|
addu a2,a2,t6 // round up to next block
|
|
addu a2,a2,t7 //
|
|
nor t6,t6,zero // complement block size minus one
|
|
and a2,a2,t6 // truncate length to even number
|
|
beq zero,a2,30f // if eq, no blocks to flush
|
|
and t8,t0,t6 // compute starting virtual address
|
|
addu t9,t8,a2 // compute ending virtual address
|
|
bne zero,v0,40f // if ne, second level cache present
|
|
subu t9,t9,t4 // compute ending loop address
|
|
|
|
//
|
|
// Flush the primary data cache only.
|
|
//
|
|
|
|
20: cache HIT_WRITEBACK_INVALIDATE_D,0(t8) // invalidate cache block
|
|
bne t8,t9,20b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
30: ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
//
|
|
// Flush the primary and secondary data caches.
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
40: cache HIT_WRITEBACK_INVALIDATE_SD,0(t8) // invalidate cache block
|
|
bne t8,t9,40b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
.end HalFlushDcachePage
|
|
|
|
|
|
SBTTL("Purge Data Cache Page")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalPurgeDcachePage (
|
|
// IN PVOID Color,
|
|
// IN ULONG PageFrame,
|
|
// IN ULONG Length
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function purges (hit/invalidate) up to a page of data from the
|
|
// data cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Color (a0) - Supplies the starting virtual address and color of the
|
|
// data that is purged.
|
|
//
|
|
// PageFrame (a1) - Supplies the page frame number of the page that
|
|
// is purged.
|
|
//
|
|
// Length (a2) - Supplies the length of the region in the page that is
|
|
// purged.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(HalPurgeDcachePage)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeDcacheFlushCount // get address of dcache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result
|
|
|
|
#endif
|
|
|
|
//
|
|
// Determine if the ECache is
|
|
// present (active) which means
|
|
// it is enabled.
|
|
//
|
|
la t0,HalpPmpExternalCachePresent
|
|
lw t0,0(t0)
|
|
beq t0,zero, noECachePurgeDcachePage
|
|
|
|
DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
//
|
|
// Calculate the tlb mapping values
|
|
// and determine which half of the
|
|
// tlb entry to use for the on-chip
|
|
// cache.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
|
|
and a0,a0,COLOR_MASK // isolate color bits
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a0 // compute color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a0,a0,0x1000 // isolate TB entry index
|
|
beql zero,a0,11f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
11: mfc0 t3,wired // get TB entry index
|
|
lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
|
|
lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
|
|
bnel zero,v0,16f // if ne, second level cache present
|
|
move t4,v0 // set purge block size
|
|
|
|
//
|
|
// Now calculate the tlb mapping values
|
|
// for the ECache invalidate space and
|
|
// use the other "unused" tlb entry.
|
|
//
|
|
16:
|
|
li t6, (ECACHE_CONTROL_PHYSICAL_BASE >> 2)
|
|
li t7, ((ECACHE_CONTROL_PHYSICAL_BASE >> PAGE_SHIFT) << ENTRYLO_PFN)
|
|
or t6, t6, t7
|
|
li t7, (((512*1024)-1) >> PAGE_SHIFT)
|
|
and t7, a1, t7
|
|
sll t7, t7, ENTRYLO_PFN
|
|
or t6, t6, t7
|
|
li t7, ECACHE_PROTECTION_BITS
|
|
or t6, t6, t7
|
|
|
|
move a3, zero
|
|
beql t1, zero, 17f
|
|
move t1, t6
|
|
|
|
move t2, t6
|
|
addiu a3, a3, 1
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Now we actually do the mapping
|
|
// by directly writing the TLB
|
|
//
|
|
17:
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
subu t6,t4,1 // compute block size minus one
|
|
and t7,t0,t6 // compute offset in block
|
|
addu a2,a2,t6 // round up to next block
|
|
addu a2,a2,t7 //
|
|
nor t6,t6,zero // complement block size minus one
|
|
and a2,a2,t6 // truncate length to even number
|
|
beq zero,a2,31f // if eq, no blocks to purge
|
|
and t8,t0,t6 // compute starting virtual address
|
|
addu t9,t8,a2 // compute ending virtual address
|
|
subu t9,t9,t4 // compute ending loop address
|
|
|
|
//
|
|
// Now we use the mapped
|
|
// vaddr based on which half
|
|
// of the tlb entry we used
|
|
// for the ECache mapping.
|
|
//
|
|
move t6, t8
|
|
li t7, PAGE_SIZE
|
|
beql a3, zero, 21f
|
|
subu t6, t6, t7
|
|
|
|
addu t6, t6, t7
|
|
|
|
//
|
|
// Purge the primary data cache and
|
|
// invalidate the external cache.
|
|
//
|
|
21: cache HIT_INVALIDATE_D,0(t8) // invalidate cache block
|
|
nop
|
|
sw zero,0(t6) // ECache line invalidate
|
|
addu t6,t6,t4 // compute next address
|
|
bne t8,t9,21b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Now we will mark the ECache page
|
|
// invalid before exiting ...
|
|
//
|
|
31:
|
|
.set noreorder
|
|
.set noat
|
|
|
|
#if 1
|
|
|
|
//mtc0 zero, entrylo0
|
|
//mtc0 zero, entrylo1
|
|
//nop
|
|
|
|
#else
|
|
|
|
beq zero, a3, 22f
|
|
nop
|
|
|
|
mtc0 zero, entrylo1
|
|
b 23f
|
|
nop
|
|
|
|
22:
|
|
mtc0 zero, entrylo0
|
|
nop
|
|
|
|
23:
|
|
|
|
#endif
|
|
|
|
//nop
|
|
//nop
|
|
//nop
|
|
//tlbwi
|
|
//nop
|
|
//nop
|
|
//nop
|
|
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
|
|
//
|
|
// This section of code is only executed
|
|
// if the processor is not an R4600/R4700 or
|
|
// it is an R4600/R4700 but there is no ECache.
|
|
//
|
|
noECachePurgeDcachePage:
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
|
|
and a0,a0,COLOR_MASK // isolate color bits
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a0 // compute color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a0,a0,0x1000 // isolate TB entry index
|
|
beql zero,a0,10f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
10: mfc0 t3,wired // get TB entry index
|
|
lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
|
|
lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
|
|
bnel zero,v0,15f // if ne, second level cache present
|
|
move t4,v0 // set purge block size
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Purge data from the data cache.
|
|
//
|
|
|
|
15: DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
subu t6,t4,1 // compute block size minus one
|
|
and t7,t0,t6 // compute offset in block
|
|
addu a2,a2,t6 // round up to next block
|
|
addu a2,a2,t7 //
|
|
nor t6,t6,zero // complement block size minus one
|
|
and a2,a2,t6 // truncate length to even number
|
|
beq zero,a2,30f // if eq, no blocks to purge
|
|
and t8,t0,t6 // compute starting virtual address
|
|
addu t9,t8,a2 // compute ending virtual address
|
|
bne zero,v0,40f // if ne, second level cache present
|
|
subu t9,t9,t4 // compute ending loop address
|
|
|
|
//
|
|
// Purge the primary data cache only.
|
|
//
|
|
|
|
20: cache HIT_INVALIDATE_D,0(t8) // invalidate cache block
|
|
bne t8,t9,20b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
30: ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
//
|
|
// Purge the primary and secondary data caches.
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
40: cache HIT_INVALIDATE_SD,0(t8) // invalidate cache block
|
|
bne t8,t9,40b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
.end HalPurgeDcachePage
|
|
|
|
SBTTL("Purge Instruction Cache Page")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalPurgeIcachePage (
|
|
// IN PVOID Color,
|
|
// IN ULONG PageFrame,
|
|
// IN ULONG Length
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function purges (hit/invalidate) up to a page of data from the
|
|
// instruction cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Color (a0) - Supplies the starting virtual address and color of the
|
|
// data that is purged.
|
|
//
|
|
// PageFrame (a1) - Supplies the page frame number of the page that
|
|
// is purged.
|
|
//
|
|
// Length (a2) - Supplies the length of the region in the page that is
|
|
// purged.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(HalPurgeIcachePage)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeIcacheFlushCount // get address of icache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result
|
|
|
|
#endif
|
|
|
|
//
|
|
// Determine if the ECache is
|
|
// present (active) which means
|
|
// it is enabled.
|
|
//
|
|
la t0,HalpPmpExternalCachePresent
|
|
lw t0,0(t0)
|
|
beq t0,zero, noECachePurgeIcachePage
|
|
|
|
DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
//
|
|
// Calculate the tlb mapping values
|
|
// and determine which half of the
|
|
// tlb entry to use for the on-chip
|
|
// cache.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
|
|
and a0,a0,COLOR_MASK // isolate color bits
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a0 // compute color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a0,a0,0x1000 // isolate TB entry index
|
|
beql zero,a0,11f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
11: mfc0 t3,wired // get TB entry index
|
|
lw v0,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size
|
|
lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size
|
|
bnel zero,v0,16f // if ne, second level cache present
|
|
move t4,v0 // set purge block size
|
|
|
|
//
|
|
// Now calculate the tlb mapping values
|
|
// for the ECache invalidate space and
|
|
// use the other "unused" tlb entry.
|
|
//
|
|
16:
|
|
|
|
li t6, (ECACHE_CONTROL_PHYSICAL_BASE >> 2)
|
|
li t7, ((ECACHE_CONTROL_PHYSICAL_BASE >> PAGE_SHIFT) << ENTRYLO_PFN)
|
|
or t6, t6, t7
|
|
li t7, (((512*1024)-1) >> PAGE_SHIFT)
|
|
and t7, a1, t7
|
|
sll t7, t7, ENTRYLO_PFN
|
|
or t6, t6, t7
|
|
li t7, ECACHE_PROTECTION_BITS
|
|
or t6, t6, t7
|
|
|
|
move a3, zero
|
|
beql t1, zero, 17f
|
|
move t1, t6
|
|
|
|
move t2, t6
|
|
addiu a3, a3, 1
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Now we actually do the mapping
|
|
// by directly writing the TLB
|
|
//
|
|
17:
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
subu t6,t4,1 // compute block size minus one
|
|
and t7,t0,t6 // compute offset in block
|
|
addu a2,a2,t6 // round up to next block
|
|
addu a2,a2,t7 //
|
|
nor t6,t6,zero // complement block size minus one
|
|
and a2,a2,t6 // truncate length to even number
|
|
beq zero,a2,31f // if eq, no blocks to purge
|
|
and t8,t0,t6 // compute starting virtual address
|
|
addu t9,t8,a2 // compute ending virtual address
|
|
subu t9,t9,t4 // compute ending loop address
|
|
|
|
//
|
|
// Now we use the mapped
|
|
// vaddr based on which half
|
|
// of the tlb entry we used
|
|
// for the ECache mapping.
|
|
//
|
|
move t6, t8
|
|
li t7, PAGE_SIZE
|
|
beql a3, zero, 21f
|
|
subu t6, t6, t7
|
|
|
|
addu t6, t6, t7
|
|
|
|
//
|
|
// Purge the primary instruction cache and
|
|
// invalidate the external cache.
|
|
//
|
|
21: cache HIT_INVALIDATE_I,0(t8) // invalidate cache block
|
|
nop
|
|
sw zero,0(t6) // ECache line invalidate
|
|
addu t6,t6,t4 // compute next address
|
|
bne t8,t9,21b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Now we will mark the ECache page
|
|
// invalid before exiting ...
|
|
//
|
|
31:
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
//
|
|
// This section of code is only executed
|
|
// if the processor is not an R4600/R4700 or
|
|
// it is an R4600/R4700 but there is no ECache.
|
|
//
|
|
noECachePurgeIcachePage:
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
|
|
and a0,a0,COLOR_MASK // isolate color bits
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a0 // compute color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a0,a0,0x1000 // isolate TB entry index
|
|
beql zero,a0,10f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
10: mfc0 t3,wired // get TB entry index
|
|
lw v0,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size
|
|
lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size
|
|
bnel zero,v0,15f // if ne, second level cache present
|
|
move t4,v0 // set purge block size
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Purge data from the instruction cache.
|
|
//
|
|
|
|
15: DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
subu t6,t4,1 // compute block size minus one
|
|
and t7,t0,t6 // compute offset in block
|
|
addu a2,a2,t6 // round up to next block
|
|
addu a2,a2,t7 //
|
|
nor t6,t6,zero // complement block size minus one
|
|
and a2,a2,t6 // truncate length to even number
|
|
beq zero,a2,30f // if eq, no blocks to purge
|
|
and t8,t0,t6 // compute starting virtual address
|
|
addu t9,t8,a2 // compute ending virtual address
|
|
bne zero,v0,40f // if ne, second level cache present
|
|
subu t9,t9,t4 // compute ending loop address
|
|
|
|
//
|
|
// Purge the primary instruction cache only.
|
|
//
|
|
|
|
20: cache HIT_INVALIDATE_I,0(t8) // invalidate cache block
|
|
bne t8,t9,20b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
30: ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
//
|
|
// Purge the primary and secondary instruction caches.
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
40: cache HIT_INVALIDATE_SI,0(t8) // invalidate cache block
|
|
bne t8,t9,40b // if ne, more blocks to invalidate
|
|
addu t8,t8,t4 // compute next block address
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra // return
|
|
|
|
.end HalPurgeIcachePage
|
|
|
|
SBTTL("Sweep Data Cache")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalpSweepDcache (
|
|
// VOID
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sweeps (index/writeback/invalidate) the entire data cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// a0 contains the virtual address of the ECache invalidate
|
|
// register (if enabled); otherwise, it is NULL.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(HalpSweepDcache)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeDcacheFlushCount // get address of dcache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result
|
|
|
|
#endif
|
|
|
|
//
|
|
// Determine if ECache is active
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
beq a0, zero, noECacheSweepDcache
|
|
nop
|
|
|
|
//
|
|
// Get vaddr of ECache invalidate register
|
|
//
|
|
lw t2, HalpExtPmpControl
|
|
.set at
|
|
.set reorder
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This section is executed only
|
|
// if the sweep routine was called
|
|
// via HalFlushIoBuffer()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
ECacheSweepDcache:
|
|
|
|
DISABLE_INTERRUPTS(t5)
|
|
|
|
lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size
|
|
lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
//
|
|
// Determine if this is an R4600/R4700
|
|
// and if so then we need to deal
|
|
// with the two-way set associativity.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t3, prid
|
|
nop
|
|
nop
|
|
nop
|
|
li t0, 2
|
|
srl t3, t3, 12
|
|
bne t3, t0, 60f
|
|
nop
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary data cache (R4600/R4700 only).
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
50: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
|
|
nop // fill
|
|
cache INDEX_WRITEBACK_INVALIDATE_D,8192(a0) // writeback/invalidate on index
|
|
bne a0,a1,50b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Invalidate the ECache
|
|
//
|
|
lb t1, 0(t2) // External PMP Control
|
|
ori t1, t1, 1
|
|
sb t1, 0(t2)
|
|
andi t1, t1, 0xFE
|
|
sb t1, 0(t2)
|
|
ori t1, t1, 1
|
|
sb t1, 0(t2)
|
|
lb zero, 0(t2) // External cache INVALIDATED
|
|
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra
|
|
|
|
//
|
|
// Sweep the primary data cache (except R4600/R4700).
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
60: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
|
|
bne a0,a1,60b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Invalidate the ECache
|
|
//
|
|
lb t1, 0(t2) // External PMP Control
|
|
ori t1, t1, 1
|
|
sb t1, 0(t2)
|
|
andi t1, t1, 0xFE
|
|
sb t1, 0(t2)
|
|
ori t1, t1, 1
|
|
sb t1, 0(t2)
|
|
lb zero, 0(t2) // External cache INVALIDATED
|
|
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// This section of code is executed
|
|
// there is no ECache active ...
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
noECacheSweepDcache:
|
|
|
|
lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size
|
|
lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
//
|
|
// Determine if this is an R4600/R4700
|
|
// and if so then we need to deal
|
|
// with the two-way set associativity.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t3, prid
|
|
nop
|
|
nop
|
|
nop
|
|
li t0, 2
|
|
srl t3, t3, 12
|
|
bne t3, t0, 10f
|
|
nop
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary data cache (R4600/R4700 only).
|
|
//
|
|
|
|
DISABLE_INTERRUPTS(t5)
|
|
|
|
.set noreorder
|
|
.set noat
|
|
50: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
|
|
nop // fill
|
|
cache INDEX_WRITEBACK_INVALIDATE_D,8192(a0) // writeback/invalidate on index
|
|
bne a0,a1,50b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra // return
|
|
|
|
//
|
|
// Sweep the primary data cache (except R4600/R4700).
|
|
//
|
|
|
|
10:
|
|
DISABLE_INTERRUPTS(t5)
|
|
|
|
.set noreorder
|
|
.set noat
|
|
11: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
|
|
bne a0,a1,11b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size
|
|
lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size
|
|
beq zero,t1,40f // if eq, no second level cache
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
//
|
|
// Sweep the secondary data cache (except R4600/R4700).
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
20: cache INDEX_WRITEBACK_INVALIDATE_SD,0(a0) // writeback/invalidate on index
|
|
bne a0,a1,20b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
40:
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra // return
|
|
|
|
.end HalpSweepDcache
|
|
|
|
SBTTL("Sweep Data Cache Range")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalSweepDcacheRange (
|
|
// IN PVOID BaseAddress,
|
|
// IN ULONG Length
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sweeps (index/writeback/invalidate) the specified range
|
|
// of virtual addresses from the primary data cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// BaseAddress (a0) - Supplies the base address of the range that is swept
|
|
// from the data cache.
|
|
//
|
|
// Length (a1) - Supplies the length of the range that is swept from the
|
|
// data cache.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(HalSweepDcacheRange)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeDcacheFlushCount // get address of dcache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result conditionally
|
|
|
|
#endif
|
|
|
|
and a0,a0,COLOR_MASK // isolate color and offset bits
|
|
or a0,a0,KSEG0_BASE // convert to physical address
|
|
lw t0,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size
|
|
addu a1,a0,a1 // compute ending cache address
|
|
subu a1,a1,t0 // compute ending block address
|
|
|
|
//
|
|
// Determine if this is an R4600/R4700
|
|
// and if so then we need to deal
|
|
// with the two-way set associativity.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t1, prid
|
|
nop
|
|
nop
|
|
nop
|
|
li t2, 2
|
|
srl t1, t1, 12
|
|
bne t1, t2, 20f
|
|
nop
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary data cache (only R4600/R4700).
|
|
//
|
|
|
|
DISABLE_INTERRUPTS(t5)
|
|
|
|
.set noreorder
|
|
.set noat
|
|
10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
|
|
nop
|
|
cache INDEX_WRITEBACK_INVALIDATE_D,8192(a0) // do other set on Orion
|
|
bne a0,a1,10b // if ne, more to invalidate
|
|
addu a0,a0,t0 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra
|
|
|
|
//
|
|
// Sweep the primary data cache (except R4600/R4700).
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
20: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
|
|
bne a0,a1,20b // if ne, more to invalidate
|
|
addu a0,a0,t0 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
j ra // return
|
|
|
|
.end HalSweepDcacheRange
|
|
|
|
SBTTL("Sweep Instruction Cache")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalpSweepIcache (
|
|
// VOID
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sweeps (index/invalidate) the entire instruction cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// a0 contains the virtual address of the ECache invalidate
|
|
// register (if enabled); otherwise, it is NULL.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(HalpSweepIcache)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeIcacheFlushCount // get address of icache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result
|
|
|
|
#endif
|
|
|
|
//
|
|
// Determine if ECache is active
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
beq a0, zero, noECacheSweepIcache
|
|
nop
|
|
|
|
//
|
|
// Get vaddr of ECache invalidate register
|
|
//
|
|
lw t2, HalpExtPmpControl
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Invalidate the External Cache
|
|
//
|
|
ECacheSweepIcache:
|
|
|
|
DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
lb t1, 4(t2)
|
|
ori t1, t1, 1
|
|
sb t1, 4(t2)
|
|
andi t1, t1, 0xFE
|
|
sb t1, 4(t2)
|
|
ori t1, t1, 1
|
|
sb t1, 4(t2)
|
|
lb zero, 4(t2) // ECache INVALIDATED
|
|
|
|
|
|
lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size
|
|
lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
//
|
|
// Determine if this is an R4600/R4700
|
|
// and if so then we need to deal
|
|
// with the two-way set associativity.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t3, prid
|
|
nop
|
|
nop
|
|
nop
|
|
li t2, 2
|
|
srl t3, t3, 12
|
|
bne t3, t2, 60f
|
|
nop
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary instruction cache (R4600/R4700 only).
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
50: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
|
|
nop // fill
|
|
cache INDEX_INVALIDATE_I,8192(a0) // writeback/invalidate on index
|
|
bne a0,a1,50b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra
|
|
|
|
//
|
|
// Sweep the primary instruction cache (except R4600/R4700).
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
60: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
|
|
bne a0,a1,60b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra
|
|
|
|
//
|
|
// No ECache section
|
|
//
|
|
noECacheSweepIcache:
|
|
|
|
//
|
|
// Determine if this is an R4600/R4700
|
|
// and if so then we need to deal
|
|
// with the two-way set associativity.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t3, prid
|
|
nop
|
|
nop
|
|
nop
|
|
li t2, 2
|
|
srl t3, t3, 12
|
|
bne t3, t2, 60f
|
|
nop
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary instruction cache (R4600/R4700 only).
|
|
//
|
|
lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size
|
|
lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
DISABLE_INTERRUPTS(t0) // disable interrupts
|
|
|
|
.set noreorder
|
|
.set noat
|
|
50: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
|
|
nop // fill
|
|
cache INDEX_INVALIDATE_I,8192(a0) // writeback/invalidate on index
|
|
bne a0,a1,50b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t0) // enable interrupts
|
|
|
|
j ra
|
|
|
|
//
|
|
// Sweep the secondary instruction cache (except R4600/R4700).
|
|
//
|
|
60:
|
|
DISABLE_INTERRUPTS(t5)
|
|
|
|
lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size
|
|
lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size
|
|
beq zero,t1,20f // if eq, no second level cache
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
.set noreorder
|
|
.set noat
|
|
10: cache INDEX_INVALIDATE_SI,0(a0) // invalidate cache line
|
|
bne a0,a1,10b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary instruction cache (except R4600/R4700).
|
|
//
|
|
20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size
|
|
lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
|
|
li a0,KSEG0_BASE // set starting index value
|
|
addu a1,a0,t0 // compute ending cache address
|
|
subu a1,a1,t1 // compute ending block address
|
|
|
|
.set noreorder
|
|
.set noat
|
|
40: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
|
|
bne a0,a1,40b // if ne, more to invalidate
|
|
addu a0,a0,t1 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5)
|
|
|
|
j ra // return
|
|
|
|
.end HalpSweepIcache
|
|
|
|
|
|
SBTTL("Sweep Instruction Cache Range")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalSweepIcacheRange (
|
|
// IN PVOID BaseAddress,
|
|
// IN ULONG Length
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sweeps (index/invalidate) the specified range of addresses
|
|
// from the instruction cache.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// BaseAddress (a0) - Supplies the base address of the range that is swept
|
|
// from the instruction cache.
|
|
//
|
|
// Length (a1) - Supplies the length of the range that is swept from the
|
|
// instruction cache.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(HalSweepIcacheRange)
|
|
|
|
#if DBG
|
|
|
|
lw t0,KeIcacheFlushCount // get address of icache flush count
|
|
lw t1,0(t0) // increment the count of flushes
|
|
addu t1,t1,1 //
|
|
sw t1,0(t0) // store result
|
|
|
|
#endif
|
|
|
|
and a0,a0,COLOR_MASK // isolate color and offset bits
|
|
or a0,a0,KSEG0_BASE // convert to physical address
|
|
lw t0,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
|
|
addu a1,a0,a1 // compute ending cache address
|
|
subu a1,a1,t0 // compute ending block address
|
|
|
|
//
|
|
// Determine if this is an R4600/R4700
|
|
// and if so then we need to deal
|
|
// with the two-way set associativity.
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t3, prid
|
|
nop
|
|
nop
|
|
nop
|
|
li t2, 2
|
|
srl t3, t3, 12
|
|
bne t3, t2, 20f
|
|
nop
|
|
.set at
|
|
.set reorder
|
|
|
|
//
|
|
// Sweep the primary instruction cache (only R4600/R4700)
|
|
//
|
|
|
|
DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
.set noreorder
|
|
.set noat
|
|
10: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
|
|
nop
|
|
cache INDEX_INVALIDATE_I,8192(a0) // do other set on Orion
|
|
bne a0,a1,10b // if ne, more to invalidate
|
|
addu a0,a0,t0 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
j ra
|
|
|
|
//
|
|
// Sweep the primary instruction cache (except R4600/R4700)
|
|
//
|
|
.set noreorder
|
|
.set noat
|
|
20: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
|
|
bne a0,a1,20b // if ne, more to invalidate
|
|
addu a0,a0,t0 // compute address of next block
|
|
.set at
|
|
.set reorder
|
|
|
|
j ra // return
|
|
|
|
.end HalSweepIcacheRange
|
|
|
|
SBTTL("Zero Page")
|
|
//++
|
|
//
|
|
// VOID
|
|
// HalZeroPage (
|
|
// IN PVOID NewColor,
|
|
// IN PVOID OldColor,
|
|
// IN ULONG PageFrame
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function zeros a page of memory.
|
|
//
|
|
// The algorithm used to zero a page is as follows:
|
|
//
|
|
// 1. Purge (hit/invalidate) the page from the instruction cache
|
|
// using the old color iff the old color is not the same as
|
|
// the new color.
|
|
//
|
|
// 2. Purge (hit/invalidate) the page from the data cache using
|
|
// the old color iff the old color is not the same as the new
|
|
// color.
|
|
//
|
|
// 3. Create (create/dirty/exclusive) the page in the data cache
|
|
// using the new color.
|
|
//
|
|
// 4. Write zeros to the page using the new color.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// NewColor (a0) - Supplies the page aligned virtual address of the
|
|
// new color of the page that is zeroed.
|
|
//
|
|
// OldColor (a1) - Supplies the page aligned virtual address of the
|
|
// old color of the page that is zeroed.
|
|
//
|
|
// PageFrame (a2) - Supplies the page frame number of the page that
|
|
// is zeroed.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
.struct 0
|
|
.space 3 * 4 // fill
|
|
ZpRa: .space 4 // saved return address
|
|
ZpFrameLength: // length of stack frame
|
|
ZpA0: .space 4 // (a0)
|
|
ZpA1: .space 4 // (a1)
|
|
ZpA2: .space 4 // (a2)
|
|
ZpA3: .space 4 // (a3)
|
|
|
|
NESTED_ENTRY(HalZeroPage, ZpFrameLength, zero)
|
|
|
|
subu sp,sp,ZpFrameLength // allocate stack frame
|
|
sw ra,ZpRa(sp) // save return address
|
|
|
|
PROLOGUE_END
|
|
|
|
and a0,a0,COLOR_BITS // isolate new color bits
|
|
and a1,a1,COLOR_BITS // isolate old color bits
|
|
sw a0,ZpA0(sp) // save new color bits
|
|
sw a2,ZpA2(sp) // save page frame
|
|
|
|
//
|
|
// If the old page color is not equal to the new page color, then change
|
|
// the color of the page.
|
|
//
|
|
|
|
beq a0,a1,10f // if eq, colors match
|
|
jal KeChangeColorPage // chagne page color
|
|
|
|
//
|
|
// Create dirty exclusive cache blocks and zero the data.
|
|
//
|
|
|
|
10: lw a3,ZpA0(sp) // get new color bits
|
|
lw a1,ZpA2(sp) // get page frame number
|
|
|
|
.set noreorder
|
|
.set noat
|
|
lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache polciy
|
|
li t0,FLUSH_BASE // get base flush address
|
|
or t0,t0,a3 // compute new color virtual address
|
|
sll t1,a1,ENTRYLO_PFN // shift page frame into position
|
|
or t1,t1,PROTECTION_BITS // merge protection bits
|
|
or t1,t1,v0 // merge cache policy
|
|
and a3,a3,0x1000 // isolate TB entry index
|
|
beql zero,a3,20f // if eq, first entry
|
|
move t2,zero // set second page table entry
|
|
move t2,t1 // set second page table entry
|
|
move t1,zero // set first page table entry
|
|
20: mfc0 t3,wired // get TB entry index
|
|
lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
|
|
lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
|
|
.set at
|
|
.set reorder
|
|
|
|
DISABLE_INTERRUPTS(t5) // disable interrupts
|
|
|
|
.set noreorder
|
|
.set noat
|
|
mfc0 t6,entryhi // get current PID and VPN2
|
|
srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
|
|
sll t7,t7,ENTRYHI_VPN2 //
|
|
and t6,t6,0xff << ENTRYHI_PID // isolate current PID
|
|
or t7,t7,t6 // merge PID with VPN2 of virtual address
|
|
mtc0 t7,entryhi // set VPN2 and PID for probe
|
|
mtc0 t1,entrylo0 // set first PTE value
|
|
mtc0 t2,entrylo1 // set second PTE value
|
|
mtc0 t3,index // set TB index value
|
|
nop // fill
|
|
tlbwi // write TB entry - 3 cycle hazzard
|
|
addu t9,t0,PAGE_SIZE // compute ending address of block
|
|
dmtc1 zero,f0 // set write pattern
|
|
bne zero,v0,50f // if ne, second level cache present
|
|
and t8,t4,0x10 // test if 16-byte cache block
|
|
|
|
//
|
|
// Zero page in primary data cache only.
|
|
//
|
|
|
|
30: sdc1 f0,0(t0) // zero 64-byte block
|
|
sdc1 f0,8(t0) //
|
|
sdc1 f0,16(t0) //
|
|
sdc1 f0,24(t0) //
|
|
sdc1 f0,32(t0) //
|
|
sdc1 f0,40(t0) //
|
|
sdc1 f0,48(t0) //
|
|
addu t0,t0,64 // advance to next 64-byte block
|
|
bne t0,t9,30b // if ne, more to zero
|
|
sdc1 f0,-8(t0) //
|
|
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
lw ra,ZpRa(sp) // get return address
|
|
addu sp,sp,ZpFrameLength // deallocate stack frame
|
|
j ra // return
|
|
|
|
//
|
|
// Zero page in primary and secondary data caches.
|
|
//
|
|
|
|
.set noreorder
|
|
.set noat
|
|
|
|
50: sdc1 f0,0(t0) // zero 64-byte block
|
|
sdc1 f0,8(t0) //
|
|
sdc1 f0,16(t0) //
|
|
sdc1 f0,24(t0) //
|
|
sdc1 f0,32(t0) //
|
|
sdc1 f0,40(t0) //
|
|
sdc1 f0,48(t0) //
|
|
addu t0,t0,64 // advance to next 64-byte block
|
|
bne t0,t9,50b // if ne, more to zero
|
|
sdc1 f0,-8(t0) //
|
|
|
|
.set at
|
|
.set reorder
|
|
|
|
ENABLE_INTERRUPTS(t5) // enable interrupts
|
|
|
|
lw ra,ZpRa(sp) // get return address
|
|
addu sp,sp,ZpFrameLength // deallocate stack frame
|
|
j ra // return
|
|
|
|
.end HalZeroPage
|