2005-04-17 02:20:36 +04:00
/ *
* linux/ a r c h / m 3 2 r / m m / m m u . S
*
* Copyright ( C ) 2 0 0 1 b y H i r o y u k i K o n d o
* /
# include < l i n u x / l i n k a g e . h >
# include < a s m / a s s e m b l e r . h >
# include < a s m / s m p . h >
.text
# ifdef C O N F I G _ M M U
# include < a s m / m m u _ c o n t e x t . h >
# include < a s m / p a g e . h >
# include < a s m / p g t a b l e . h >
# include < a s m / m 3 2 r . h >
/ *
* TLB M i s s E x c e p t i o n h a n d l e r
* /
.balign 16
ENTRY( t m e _ h a n d l e r )
.global tlb_entry_i_dat
.global tlb_entry_d_dat
SWITCH_ T O _ K E R N E L _ S T A C K
# if d e f i n e d ( C O N F I G _ I S A _ M 3 2 R 2 )
st r0 , @-sp
st r1 , @-sp
st r2 , @-sp
st r3 , @-sp
seth r3 , #h i g h ( M M U _ R E G _ B A S E )
ld r1 , @(MESTS_offset, r3) ; r1: status (MESTS reg.)
ld r0 , @(MDEVP_offset, r3) ; r0: PFN + ASID (MDEVP reg.)
st r1 , @(MESTS_offset, r3) ; clear status (MESTS reg.)
and3 r1 , r1 , #( M E S T S _ I T )
bnez r1 , 1 f ; instruction TLB miss?
;; data TLB miss
;; input
;; r0: PFN + ASID (MDEVP reg.)
;; r1 - r3: free
;; output
;; r0: PFN + ASID
;; r1: TLB entry base address
;; r2: &tlb_entry_{i|d}_dat
;; r3: free
# ifndef C O N F I G _ S M P
seth r2 , #h i g h ( t l b _ e n t r y _ d _ d a t )
or3 r2 , r2 , #l o w ( t l b _ e n t r y _ d _ d a t )
# else / * C O N F I G _ S M P * /
ldi r1 , #- 8192
seth r2 , #h i g h ( t l b _ e n t r y _ d _ d a t )
or3 r2 , r2 , #l o w ( t l b _ e n t r y _ d _ d a t )
and r1 , s p
ld r1 , @(16, r1) ; current_thread_info->cpu
slli r1 , #2
add r2 , r1
# endif / * ! C O N F I G _ S M P * /
seth r1 , #h i g h ( D T L B _ B A S E )
or3 r1 , r1 , #l o w ( D T L B _ B A S E )
bra 2 f
.balign 16
.fillinsn
1 :
;; instrucntion TLB miss
;; input
;; r0: MDEVP reg. (included ASID)
;; r1 - r3: free
;; output
;; r0: PFN + ASID
;; r1: TLB entry base address
;; r2: &tlb_entry_{i|d}_dat
;; r3: free
ldi r3 , #- 4096
and3 r0 , r0 , #( M M U _ C O N T E X T _ A S I D _ M A S K )
mvfc r1 , b p c
and r1 , r3
or r0 , r1 ; r0: PFN + ASID
# ifndef C O N F I G _ S M P
seth r2 , #h i g h ( t l b _ e n t r y _ i _ d a t )
or3 r2 , r2 , #l o w ( t l b _ e n t r y _ i _ d a t )
# else / * C O N F I G _ S M P * /
ldi r1 , #- 8192
seth r2 , #h i g h ( t l b _ e n t r y _ i _ d a t )
or3 r2 , r2 , #l o w ( t l b _ e n t r y _ i _ d a t )
and r1 , s p
ld r1 , @(16, r1) ; current_thread_info->cpu
slli r1 , #2
add r2 , r1
# endif / * ! C O N F I G _ S M P * /
seth r1 , #h i g h ( I T L B _ B A S E )
or3 r1 , r1 , #l o w ( I T L B _ B A S E )
.fillinsn
2 :
;; select TLB entry
;; input
;; r0: PFN + ASID
;; r1: TLB entry base address
;; r2: &tlb_entry_{i|d}_dat
;; r3: free
;; output
;; r0: PFN + ASID
;; r1: TLB entry address
;; r2, r3: free
# ifdef C O N F I G _ I S A _ D U A L _ I S S U E
ld r3 , @r2 || srli r1, #3
# else
ld r3 , @r2
srli r1 , #3
# endif
add r1 , r3
; tlb_entry_{d|i}_dat++;
addi r3 , #1
and3 r3 , r3 , #( N R _ T L B _ E N T R I E S - 1 )
# ifdef C O N F I G _ I S A _ D U A L _ I S S U E
st r3 , @r2 || slli r1, #3
# else
st r3 , @r2
slli r1 , #3
# endif
;; load pte
;; input
;; r0: PFN + ASID
;; r1: TLB entry address
;; r2, r3: free
;; output
;; r0: PFN + ASID
;; r1: TLB entry address
;; r2: pte_data
;; r3: free
; pgd = *(unsigned long *)MPTB;
ld2 4 r2 , #( - M P T B - 1 )
srl3 r3 , r0 , #22
# ifdef C O N F I G _ I S A _ D U A L _ I S S U E
not r2 , r2 | | s l l i r3 , #2 ; r3: pgd offset
# else
not r2 , r2
slli r3 , #2
# endif
ld r2 , @r2 ; r2: pgd base addr (MPTB reg.)
or r3 , r2 ; r3: pmd addr
; pmd = pmd_offset(pgd, address);
ld r3 , @r3 ; r3: pmd data
ldi r2 , #- 4096
beqz r3 , 3 f ; pmd_none(*pmd) ?
; pte = pte_offset(pmd, address);
and r2 , r3 ; r2: pte base addr
srl3 r3 , r0 , #10
and3 r3 , r3 , #0xffc ; r3: pte offset
or r3 , r2
seth r2 , #0x8000
or r3 , r2 ; r3: pte addr
; pte_data = (unsigned long)pte_val(*pte);
ld r2 , @r3 ; r2: pte data
2007-05-11 09:22:26 +04:00
and3 r3 , r2 , #2 ; _PAGE_PRESENT(=2) check
beqz r3 , 3 f
2005-04-17 02:20:36 +04:00
.fillinsn
5 :
;; set tlb
;; input
;; r0: PFN + ASID
;; r1: TLB entry address
;; r2: pte_data
;; r3: free
st r0 , @r1 ; set_tlb_tag(entry++, address);
st r2 , @+r1 ; set_tlb_data(entry, pte_data);
.fillinsn
6 :
ld r3 , @sp+
ld r2 , @sp+
ld r1 , @sp+
ld r0 , @sp+
rte
.fillinsn
3 :
;; error
;; input
;; r0: PFN + ASID
;; r1: TLB entry address
;; r2, r3: free
;; output
;; r0: PFN + ASID
;; r1: TLB entry address
;; r2: pte_data
;; r3: free
# ifdef C O N F I G _ I S A _ D U A L _ I S S U E
bra 5 b | | l d i r2 , #2
# else
ldi r2 , #2 ; r2: pte_data = 0 | _PAGE_PRESENT(=2)
bra 5 b
# endif
# elif d e f i n e d ( C O N F I G _ I S A _ M 3 2 R )
st s p , @-sp
st r0 , @-sp
st r1 , @-sp
st r2 , @-sp
st r3 , @-sp
st r4 , @-sp
seth r3 , #h i g h ( M M U _ R E G _ B A S E )
ld r0 , @(MDEVA_offset,r3) ; r0: address (MDEVA reg.)
mvfc r2 , b p c ; r2: bpc
ld r1 , @(MESTS_offset,r3) ; r1: status (MESTS reg.)
st r1 , @(MESTS_offset,r3) ; clear status (MESTS reg.)
and3 r1 , r1 , #( M E S T S _ I T )
beqz r1 , 1 f ; data TLB miss?
;; instrucntion TLB miss
mv r0 , r2 ; address = bpc;
; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2;
seth r3 , #s h i g h ( t l b _ e n t r y _ i _ d a t )
ld r4 , @(low(tlb_entry_i_dat),r3)
sll3 r2 , r4 , #3
seth r1 , #h i g h ( I T L B _ B A S E )
or3 r1 , r1 , #l o w ( I T L B _ B A S E )
add r2 , r1 ; r2: entry
addi r4 , #1 ; tlb_entry_i++;
and3 r4 , r4 , #( N R _ T L B _ E N T R I E S - 1 )
st r4 , @(low(tlb_entry_i_dat),r3)
bra 2 f
.fillinsn
1 :
;; data TLB miss
; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2;
seth r3 , #s h i g h ( t l b _ e n t r y _ d _ d a t )
ld r4 , @(low(tlb_entry_d_dat),r3)
sll3 r2 , r4 , #3
seth r1 , #h i g h ( D T L B _ B A S E )
or3 r1 , r1 , #l o w ( D T L B _ B A S E )
add r2 , r1 ; r2: entry
addi r4 , #1 ; tlb_entry_d++;
and3 r4 , r4 , #( N R _ T L B _ E N T R I E S - 1 )
st r4 , @(low(tlb_entry_d_dat),r3)
.fillinsn
2 :
;; load pte
; r0: address, r2: entry
; r1,r3,r4: (free)
; pgd = *(unsigned long *)MPTB;
ld2 4 r1 , #( - M P T B - 1 )
not r1 , r1
ld r1 , @r1
srl3 r4 , r0 , #22
sll3 r3 , r4 , #2
add r3 , r1 ; r3: pgd
; pmd = pmd_offset(pgd, address);
ld r1 , @r3 ; r1: pmd
beqz r1 , 3 f ; pmd_none(*pmd) ?
;
and3 r1 , r1 , #0xeff
ldi r4 , #611 ; _KERNPG_TABLE(=611)
2007-05-11 09:22:26 +04:00
bne r1 , r4 , 3 f ; !pmd_bad(*pmd) ?
2005-04-17 02:20:36 +04:00
.fillinsn
4 :
; pte = pte_offset(pmd, address);
ld r4 , @r3 ; r4: pte
ldi r3 , #- 4096
and r4 , r3
srl3 r3 , r0 , #10
and3 r3 , r3 , #0xffc
add r4 , r3
seth r3 , #0x8000
add r4 , r3 ; r4: pte
; pte_data = (unsigned long)pte_val(*pte);
ld r1 , @r4 ; r1: pte_data
2007-05-11 09:22:26 +04:00
and3 r3 , r1 , #2 ; _PAGE_PRESENT(=2) check
beqz r3 , 3 f
2005-04-17 02:20:36 +04:00
2007-05-11 09:22:26 +04:00
.fillinsn
2005-04-17 02:20:36 +04:00
;; set tlb
; r0: address, r1: pte_data, r2: entry
; r3,r4: (free)
5 :
ldi r3 , #- 4096 ; set_tlb_tag(entry++, address);
and r3 , r0
seth r4 , #s h i g h ( M A S I D )
ld r4 , @(low(MASID),r4) ; r4: MASID
and3 r4 , r4 , #( M M U _ C O N T E X T _ A S I D _ M A S K )
or r3 , r4
st r3 , @r2
2007-05-11 09:22:26 +04:00
st r1 , @(4,r2) ; set_tlb_data(entry, pte_data);
2005-04-17 02:20:36 +04:00
ld r4 , @sp+
ld r3 , @sp+
ld r2 , @sp+
ld r1 , @sp+
ld r0 , @sp+
ld s p , @sp+
rte
2007-05-11 09:22:26 +04:00
.fillinsn
3 :
ldi r1 , #2 ; r1: pte_data = 0 | _PAGE_PRESENT(=2)
bra 5 b
2005-04-17 02:20:36 +04:00
# else
# error u n k n o w n i s a c o n f i g u r a t i o n
# endif
ENTRY( i n i t _ t l b )
;; Set MMU Register
seth r0 , #h i g h ( M M U _ R E G _ B A S E ) ; S e t M M U _ R E G _ B A S E h i g h e r
or3 r0 , r0 , #l o w ( M M U _ R E G _ B A S E ) ; S e t M M U _ R E G _ B A S E l o w e r
ldi r1 , #0
st r1 , @(MPSZ_offset,r0) ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2)
ldi r1 , #0
st r1 , @(MASID_offset,r0) ; Set ASID Zero
;; Set TLB
seth r0 , #h i g h ( I T L B _ B A S E ) ; S e t I T L B _ B A S E h i g h e r
or3 r0 , r0 , #l o w ( I T L B _ B A S E ) ; S e t I T L B _ B A S E l o w e r
seth r1 , #h i g h ( D T L B _ B A S E ) ; S e t D T L B _ B A S E h i g h e r
or3 r1 , r1 , #l o w ( D T L B _ B A S E ) ; S e t D T L B _ B A S E l o w e r
ldi r2 , #0
ldi r3 , #N R _ T L B _ E N T R I E S
addi r0 , #- 4
addi r1 , #- 4
clear_tlb :
st r2 , @+r0 ; VPA <- 0
st r2 , @+r0 ; PPA <- 0
st r2 , @+r1 ; VPA <- 0
st r2 , @+r1 ; PPA <- 0
addi r3 , #- 1
bnez r3 , c l e a r _ t l b
;;
jmp r14
ENTRY( m 3 2 r _ i t l b _ e n t r y s )
ENTRY( m 3 2 r _ o t l b _ e n t r y s )
# endif / * C O N F I G _ M M U * /
2007-02-10 12:43:40 +03:00
.end