📄 tlbex-r4k.s
字号:
/* * TLB exception handling code for r4k. * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * * Multi-cpu abstraction and reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */#include <linux/config.h>#include <linux/init.h>#include <asm/asm.h>#include <asm/current.h>#include <asm/offset.h>#include <asm/cachectl.h>#include <asm/fpregdef.h>#include <asm/mipsregs.h>#include <asm/page.h>#include <asm/pgtable-bits.h>#include <asm/processor.h>#include <asm/regdef.h>#include <asm/stackframe.h>#define TLB_OPTIMIZE /* If you are paranoid, disable this. */#ifdef CONFIG_64BIT_PHYS_ADDR#define PTE_L ld#define PTE_S sd#define PTE_SRL dsrl#define P_MTC0 dmtc0#define PTE_SIZE 8#define PTEP_INDX_MSK 0xff0#define PTE_INDX_MSK 0xff8#define PTE_INDX_SHIFT 9#else#define PTE_L lw#define PTE_S sw#define PTE_SRL srl#define P_MTC0 mtc0#define PTE_SIZE 4#define PTEP_INDX_MSK 0xff8#define PTE_INDX_MSK 0xffc#define PTE_INDX_SHIFT 10#endif __INIT#ifdef CONFIG_64BIT_PHYS_ADDR#define GET_PTE_OFF(reg)#elif CONFIG_CPU_VR41XX#define GET_PTE_OFF(reg) srl reg, reg, 3#else#define GET_PTE_OFF(reg) srl reg, reg, 1#endif/* * These handlers much be written in a relocatable manner * because based upon the cpu type an arbitrary one of the * following pieces of code will be copied to the KSEG0 * vector location. */ /* TLB refill, EXL == 0, R4xx0, non-R4600 version */ .set noreorder .set noat LEAF(except_vec0_r4000) .set mips3#ifdef CONFIG_SMP mfc0 k1, CP0_CONTEXT la k0, pgd_current srl k1, 23 sll k1, 2 # log2(sizeof(pgd_t) addu k1, k0, k1 lw k1, (k1)#else lw k1, pgd_current # get pgd pointer#endif mfc0 k0, CP0_BADVADDR # Get faulting address srl k0, k0, _PGDIR_SHIFT # get pgd only bits sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset mfc0 k0, CP0_CONTEXT # get context reg lw k1, (k1) GET_PTE_OFF(k0) # get pte offset and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 # add in offset PTE_L k0, 0(k1) # get even pte PTE_L k1, PTE_SIZE(k1) # get odd pte PTE_SRL k0, k0, 6 # convert to entrylo0 P_MTC0 k0, CP0_ENTRYLO0 # load it PTE_SRL k1, k1, 6 # convert to entrylo1 P_MTC0 k1, CP0_ENTRYLO1 # load it b 1f tlbwr # write random tlb entry1: nop eret # return from trap END(except_vec0_r4000) /* TLB refill, EXL == 0, R4600 version */ LEAF(except_vec0_r4600) .set mips3 mfc0 k0, CP0_BADVADDR srl k0, k0, _PGDIR_SHIFT lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1)#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 PTE_L k0, 0(k1) PTE_L k1, PTE_SIZE(k1) PTE_SRL k0, k0, 6 P_MTC0 k0, CP0_ENTRYLO0 PTE_SRL k1, k1, 6 P_MTC0 k1, CP0_ENTRYLO1 nop tlbwr nop eret END(except_vec0_r4600) /* TLB refill, EXL == 0, R52x0 "Nevada" version */ /* * This version has a bug workaround for the Nevada. It seems * as if under certain circumstances the move from cp0_context * might produce a bogus result when the mfc0 instruction and * it's consumer are in a different cacheline or a load instruction, * probably any memory reference, is between them. This is * potencially slower than the R4000 version, so we use this * special version. */ .set noreorder .set noat LEAF(except_vec0_nevada) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address srl k0, k0, _PGDIR_SHIFT # get pgd only bits lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 # add in pgd offset lw k1, (k1) mfc0 k0, CP0_CONTEXT # get context reg#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1 # get pte offset#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 # add in offset PTE_L k0, 0(k1) # get even pte PTE_L k1, PTE_SIZE(k1) # get odd pte PTE_SRL k0, k0, 6 # convert to entrylo0 P_MTC0 k0, CP0_ENTRYLO0 # load it PTE_SRL k1, k1, 6 # convert to entrylo1 P_MTC0 k1, CP0_ENTRYLO1 # load it nop # QED specified nops nop tlbwr # write random tlb entry nop # traditional nop eret # return from trap END(except_vec0_nevada) /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */ LEAF(except_vec0_r45k_bvahwbug) .set mips3 mfc0 k0, CP0_BADVADDR srl k0, k0, _PGDIR_SHIFT lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1)#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 PTE_L k0, 0(k1) PTE_L k1, PTE_SIZE(k1) nop /* XXX */ tlbp PTE_SRL k0, k0, 6 P_MTC0 k0, CP0_ENTRYLO0 PTE_SRL k1, k1, 6 mfc0 k0, CP0_INDEX P_MTC0 k1, CP0_ENTRYLO1 bltzl k0, 1f tlbwr1: nop eret END(except_vec0_r45k_bvahwbug)#ifdef CONFIG_SMP /* TLB refill, EXL == 0, R4000 MP badvaddr hwbug version */ LEAF(except_vec0_r4k_mphwbug) .set mips3 mfc0 k0, CP0_BADVADDR srl k0, k0, _PGDIR_SHIFT lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1)#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 PTE_L k0, 0(k1) PTE_L k1, PTE_SIZE(k1) nop /* XXX */ tlbp PTE_SRL k0, k0, 6 P_MTC0 k0, CP0_ENTRYLO0 PTE_SRL k1, k1, 6 mfc0 k0, CP0_INDEX P_MTC0 k1, CP0_ENTRYLO1 bltzl k0, 1f tlbwr1: nop eret END(except_vec0_r4k_mphwbug)#endif /* TLB refill, EXL == 0, R4000 UP 250MHZ entrylo[01] hwbug version */ LEAF(except_vec0_r4k_250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR srl k0, k0, _PGDIR_SHIFT lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1)#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 PTE_L k0, 0(k1) PTE_L k1, PTE_SIZE(k1) PTE_SRL k0, k0, 6 P_MTC0 zero, CP0_ENTRYLO0 P_MTC0 k0, CP0_ENTRYLO0 PTE_SRL k1, k1, 6 P_MTC0 zero, CP0_ENTRYLO1 P_MTC0 k1, CP0_ENTRYLO1 b 1f tlbwr1: nop eret END(except_vec0_r4k_250MHZhwbug)#ifdef CONFIG_SMP /* TLB refill, EXL == 0, R4000 MP 250MHZ entrylo[01]+badvaddr bug version */ LEAF(except_vec0_r4k_MP250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR srl k0, k0, _PGDIR_SHIFT lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1)#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 PTE_L k0, 0(k1) PTE_L k1, PTE_SIZE(k1) nop /* XXX */ tlbp PTE_SRL k0, k0, 6 P_MTC0 zero, CP0_ENTRYLO0 P_MTC0 k0, CP0_ENTRYLO0 mfc0 k0, CP0_INDEX PTE_SRL k1, k1, 6 P_MTC0 zero, CP0_ENTRYLO1 P_MTC0 k1, CP0_ENTRYLO1 bltzl k0, 1f tlbwr1: nop eret END(except_vec0_r4k_MP250MHZhwbug)#endif#ifdef CONFIG_MIPS_AU1000 /* TLB refill, EXL == 0, Au1000 version */ /* we'll worry about smp later */ .set noreorder .set noat LEAF(except_vec0_au1000) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address srl k0, k0, _PGDIR_SHIFT # get pgd only bits lw k1, pgd_current # get pgd pointer sll k0, k0, 2 # log2(sizeof(pgd_t) addu k1, k1, k0 # add in pgd offset mfc0 k0, CP0_CONTEXT # get context reg lw k1, (k1)#ifndef CONFIG_64BIT_PHYS_ADDR srl k0, k0, 1 # get pte offset#endif and k0, k0, PTEP_INDX_MSK addu k1, k1, k0 # add in offset j translate_pte nop END(except_vec0_au1000)#endif __FINIT/* * ABUSE of CPP macros 101. * * After this macro runs, the pte faulted on is * in register PTE, a ptr into the table in which * the pte belongs is in PTR. */#ifdef CONFIG_SMP#define GET_PGD(scratch, ptr) \ mfc0 ptr, CP0_CONTEXT; \ la scratch, pgd_current;\ srl ptr, 23; \ sll ptr, 2; \ addu ptr, scratch, ptr; \ lw ptr, (ptr); #else#define GET_PGD(scratch, ptr) \ lw ptr, pgd_current;#endif#define LOAD_PTE(pte, ptr) \ GET_PGD(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ srl pte, pte, _PGDIR_SHIFT; \ sll pte, pte, 2; \ addu ptr, ptr, pte; \ mfc0 pte, CP0_BADVADDR; \ lw ptr, (ptr); \ srl pte, pte, PTE_INDX_SHIFT; \ and pte, pte, PTE_INDX_MSK; \ addu ptr, ptr, pte; \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -