| /* alpha_ev5_cons.c - Alpha console support routines for EV5 | |
| Copyright (c) 2003-2006, Robert M Supnik | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of Robert M Supnik shall not be | |
| used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from Robert M Supnik. | |
| */ | |
| #include "alpha_defs.h" | |
| #include "alpha_ev5_defs.h" | |
| t_uint64 srm_ptbr = 1; | |
| extern uint32 dtlb_spage; | |
| extern uint32 pal_type; | |
| extern uint32 ev5_mcsr; | |
| extern t_uint64 *M; | |
| extern t_uint64 ev5_mvptbr; | |
| extern UNIT cpu_unit; | |
| /* Local quadword physical read - <no> exceptions or IO space lookups */ | |
| t_stat l_ReadPQ (t_uint64 pa, t_uint64 *dat) | |
| { | |
| if (ADDR_IS_MEM (pa)) { | |
| *dat = M[pa >> 3]; | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /* "SRM" 3-level pte lookup | |
| Inputs: | |
| va = virtual address | |
| *pte = pointer to pte to be returned | |
| Output: | |
| status = 0 for successful fill | |
| EXC_ACV for ACV on intermediate level | |
| EXC_TNV for TNV on intermediate level | |
| */ | |
| uint32 cons_find_pte_srm (t_uint64 va, t_uint64 *l3pte) | |
| { | |
| t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; | |
| uint32 vpte_vpn; | |
| TLBENT *vpte_p; | |
| vptea = FMT_MVA_VMS (va); /* try virt lookup */ | |
| vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ | |
| vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ | |
| if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) | |
| l3ptea = PHYS_ADDR (vpte_p->pfn, vptea); | |
| else { | |
| uint32 vpn = VA_GETVPN (va); | |
| if (srm_ptbr & 1) return 1; /* uninitialized? */ | |
| l1ptea = srm_ptbr + VPN_GETLVL1 (vpn); | |
| if (!l_ReadPQ (l1ptea, &l1pte)) return 1; | |
| if ((l1pte & PTE_V) == 0) | |
| return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); | |
| l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); | |
| l2ptea = l2ptea + VPN_GETLVL2 (vpn); | |
| if (!l_ReadPQ (l2ptea, &l2pte)) return 1; | |
| if ((l2pte & PTE_V) == 0) | |
| return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); | |
| l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); | |
| l3ptea = l3ptea + VPN_GETLVL3 (vpn); | |
| } | |
| if (!l_ReadPQ (l3ptea, l3pte)) return 1; | |
| return 0; | |
| } | |
| /* NT 2-level pte lookup | |
| Inputs: | |
| va = virtual address | |
| *pte = pointer to pte to be returned | |
| Output: | |
| status = 0 for successful fill | |
| EXC_ACV for ACV on intermediate level | |
| EXC_TNV for TNV on intermediate level | |
| */ | |
| uint32 cons_find_pte_nt (t_uint64 va, t_uint64 *l3pte) | |
| { | |
| t_uint64 vptea, l3ptea; | |
| uint32 vpte_vpn; | |
| TLBENT *vpte_p; | |
| vptea = FMT_MVA_NT (va); /* try virt lookup */ | |
| vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ | |
| vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ | |
| if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) | |
| l3ptea = PHYS_ADDR (vpte_p->pfn, vptea); | |
| else { | |
| return 1; /* for now */ | |
| } | |
| if (!l_ReadPQ (l3ptea, l3pte)) return 1; | |
| return 0; | |
| } | |
| /* Translate address for console access */ | |
| t_uint64 trans_c (t_uint64 va) | |
| { | |
| uint32 va_sext = VA_GETSEXT (va); | |
| uint32 vpn = VA_GETVPN (va); | |
| TLBENT *tlbp; | |
| t_uint64 pte64; | |
| uint32 exc, pfn; | |
| if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ | |
| return M64; | |
| if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) | |
| return (va & SP43_MASK); /* 43b superpage? */ | |
| if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) | |
| return (va & SP32_MASK); /* 32b superpage? */ | |
| if ((tlbp = dtlb_lookup (vpn))) /* try TLB */ | |
| return PHYS_ADDR (tlbp->pfn, va); /* found it */ | |
| if (ev5_mcsr & MCSR_NT) exc = cons_find_pte_nt (va, &pte64); | |
| else exc = cons_find_pte_srm (va, &pte64); | |
| if (exc || ((pte64 & PTE_V) == 0)) return M64; /* check valid */ | |
| pfn = (uint32) (pte64 >> 32) & M32; | |
| return PHYS_ADDR (pfn, va); /* return phys addr */ | |
| } |