| ############################################################################### |
| # |
| # TLB loading functions |
| # |
| # Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. |
| # Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
| # Modified by David Howells (dhowells@redhat.com) |
| # |
| # This program is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU General Public Licence |
| # as published by the Free Software Foundation; either version |
| # 2 of the Licence, or (at your option) any later version. |
| # |
| ############################################################################### |
| #include <linux/sys.h> |
| #include <linux/linkage.h> |
| #include <asm/smp.h> |
| #include <asm/intctl-regs.h> |
| #include <asm/frame.inc> |
| #include <asm/page.h> |
| #include <asm/pgtable.h> |
| |
| ############################################################################### |
| # |
| # Instruction TLB Miss handler entry point |
| # |
| ############################################################################### |
| .type itlb_miss,@function |
| ENTRY(itlb_miss) |
| #ifdef CONFIG_GDBSTUB |
| movm [d2,d3,a2],(sp) |
| #else |
| or EPSW_nAR,epsw # switch D0-D3 & A0-A3 to the alternate |
| # register bank |
| nop |
| nop |
| nop |
| #endif |
| |
| #if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) |
| mov (MMUCTR),d2 |
| mov d2,(MMUCTR) |
| #endif |
| |
| and ~EPSW_NMID,epsw |
| mov (IPTEU),d3 |
| mov (PTBR),a2 |
| mov d3,d2 |
| and 0xffc00000,d2 |
| lsr 20,d2 |
| mov (a2,d2),a2 # PTD *ptd = PGD[addr 31..22] |
| btst _PAGE_VALID,a2 |
| beq itlb_miss_fault # jump if doesn't point anywhere |
| |
| and ~(PAGE_SIZE-1),a2 |
| mov d3,d2 |
| and 0x003ff000,d2 |
| lsr 10,d2 |
| add d2,a2 |
| mov (a2),d2 # get pte from PTD[addr 21..12] |
| btst _PAGE_VALID,d2 |
| beq itlb_miss_fault # jump if doesn't point to a page |
| # (might be a swap id) |
| #if ((_PAGE_ACCESSED & 0xffffff00) == 0) |
| bset _PAGE_ACCESSED,(0,a2) |
| #elif ((_PAGE_ACCESSED & 0xffff00ff) == 0) |
| bset +(_PAGE_ACCESSED >> 8),(1,a2) |
| #else |
| #error "_PAGE_ACCESSED value is out of range" |
| #endif |
| and ~xPTEL2_UNUSED1,d2 |
| itlb_miss_set: |
| mov d2,(IPTEL2) # change the TLB |
| #ifdef CONFIG_GDBSTUB |
| movm (sp),[d2,d3,a2] |
| #endif |
| rti |
| |
| itlb_miss_fault: |
| mov _PAGE_VALID,d2 # force address error handler to be |
| # invoked |
| bra itlb_miss_set |
| |
| .size itlb_miss, . - itlb_miss |
| |
| ############################################################################### |
| # |
| # Data TLB Miss handler entry point |
| # |
| ############################################################################### |
| .type dtlb_miss,@function |
| ENTRY(dtlb_miss) |
| #ifdef CONFIG_GDBSTUB |
| movm [d2,d3,a2],(sp) |
| #else |
| or EPSW_nAR,epsw # switch D0-D3 & A0-A3 to the alternate |
| # register bank |
| nop |
| nop |
| nop |
| #endif |
| |
| #if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) |
| mov (MMUCTR),d2 |
| mov d2,(MMUCTR) |
| #endif |
| |
| and ~EPSW_NMID,epsw |
| mov (DPTEU),d3 |
| mov (PTBR),a2 |
| mov d3,d2 |
| and 0xffc00000,d2 |
| lsr 20,d2 |
| mov (a2,d2),a2 # PTD *ptd = PGD[addr 31..22] |
| btst _PAGE_VALID,a2 |
| beq dtlb_miss_fault # jump if doesn't point anywhere |
| |
| and ~(PAGE_SIZE-1),a2 |
| mov d3,d2 |
| and 0x003ff000,d2 |
| lsr 10,d2 |
| add d2,a2 |
| mov (a2),d2 # get pte from PTD[addr 21..12] |
| btst _PAGE_VALID,d2 |
| beq dtlb_miss_fault # jump if doesn't point to a page |
| # (might be a swap id) |
| #if ((_PAGE_ACCESSED & 0xffffff00) == 0) |
| bset _PAGE_ACCESSED,(0,a2) |
| #elif ((_PAGE_ACCESSED & 0xffff00ff) == 0) |
| bset +(_PAGE_ACCESSED >> 8),(1,a2) |
| #else |
| #error "_PAGE_ACCESSED value is out of range" |
| #endif |
| and ~xPTEL2_UNUSED1,d2 |
| dtlb_miss_set: |
| mov d2,(DPTEL2) # change the TLB |
| #ifdef CONFIG_GDBSTUB |
| movm (sp),[d2,d3,a2] |
| #endif |
| rti |
| |
| dtlb_miss_fault: |
| mov _PAGE_VALID,d2 # force address error handler to be |
| # invoked |
| bra dtlb_miss_set |
| .size dtlb_miss, . - dtlb_miss |
| |
| ############################################################################### |
| # |
| # Instruction TLB Address Error handler entry point |
| # |
| ############################################################################### |
| .type itlb_aerror,@function |
| ENTRY(itlb_aerror) |
| add -4,sp |
| SAVE_ALL |
| |
| #if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) |
| mov (MMUCTR),d1 |
| mov d1,(MMUCTR) |
| #endif |
| |
| and ~EPSW_NMID,epsw |
| add -4,sp # need to pass three params |
| |
| # calculate the fault code |
| movhu (MMUFCR_IFC),d1 |
| or 0x00010000,d1 # it's an instruction fetch |
| |
| # determine the page address |
| mov (IPTEU),d0 |
| and PAGE_MASK,d0 |
| mov d0,(12,sp) |
| |
| clr d0 |
| mov d0,(IPTEL2) |
| |
| or EPSW_IE,epsw |
| mov fp,d0 |
| call do_page_fault[],0 # do_page_fault(regs,code,addr |
| |
| jmp ret_from_exception |
| .size itlb_aerror, . - itlb_aerror |
| |
| ############################################################################### |
| # |
| # Data TLB Address Error handler entry point |
| # |
| ############################################################################### |
| .type dtlb_aerror,@function |
| ENTRY(dtlb_aerror) |
| add -4,sp |
| SAVE_ALL |
| |
| #if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) |
| mov (MMUCTR),d1 |
| mov d1,(MMUCTR) |
| #endif |
| |
| add -4,sp # need to pass three params |
| and ~EPSW_NMID,epsw |
| |
| # calculate the fault code |
| movhu (MMUFCR_DFC),d1 |
| |
| # determine the page address |
| mov (DPTEU),a2 |
| mov a2,d0 |
| and PAGE_MASK,d0 |
| mov d0,(12,sp) |
| |
| clr d0 |
| mov d0,(DPTEL2) |
| |
| or EPSW_IE,epsw |
| mov fp,d0 |
| call do_page_fault[],0 # do_page_fault(regs,code,addr |
| |
| jmp ret_from_exception |
| .size dtlb_aerror, . - dtlb_aerror |