diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2005-10-03 02:18:51 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2005-10-03 02:18:51 +0000 |
commit | 2affcea6414e9b16b8e883f13257de85a53f0d9b (patch) | |
tree | d908e5b0a0c9e9be70a95c06930c90c80a815a13 /sys/arch | |
parent | 8d93507761c678254a6484c24994be455a2796dd (diff) |
G5 pmap support, most of this G5 work has been done by kettenis@
without his forging ahead, it would barely be started.
Again this is one step of many, but needs to be tested, this is
independant of the locore change just committed which kettenis@ and
deraadt@ significantly wrote.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/powerpc/include/pmap.h | 11 | ||||
-rw-r--r-- | sys/arch/powerpc/include/pte.h | 86 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/pmap.c | 676 |
3 files changed, 572 insertions, 201 deletions
diff --git a/sys/arch/powerpc/include/pmap.h b/sys/arch/powerpc/include/pmap.h index 9a6dfb9f29a..039b320cbbf 100644 --- a/sys/arch/powerpc/include/pmap.h +++ b/sys/arch/powerpc/include/pmap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.h,v 1.38 2004/08/06 22:39:13 deraadt Exp $ */ +/* $OpenBSD: pmap.h,v 1.39 2005/10/03 02:18:50 drahn Exp $ */ /* $NetBSD: pmap.h,v 1.1 1996/09/30 16:34:29 ws Exp $ */ /*- @@ -101,13 +101,14 @@ boolean_t pteclrbits(paddr_t pa, u_int mask, u_int clear); #define pmap_clear_modify(page) \ - (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_CHG, TRUE)) + (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_CHG_32, TRUE)) #define pmap_clear_reference(page) \ - (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_REF, TRUE)) + (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_REF_32, TRUE)) #define pmap_is_modified(page) \ - (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_CHG, FALSE)) + (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_CHG_32, FALSE)) #define pmap_is_referenced(page) \ - (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_REF, FALSE)) + (pteclrbits(VM_PAGE_TO_PHYS(page), PTE_REF_32, FALSE)) + #define pmap_unwire(pm, va) #define pmap_phys_address(x) (x) #define pmap_update(pmap) /* nothing (yet) */ diff --git a/sys/arch/powerpc/include/pte.h b/sys/arch/powerpc/include/pte.h index ee121a86fc1..3399c422619 100644 --- a/sys/arch/powerpc/include/pte.h +++ b/sys/arch/powerpc/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.7 2003/01/30 15:38:09 drahn Exp $ */ +/* $OpenBSD: pte.h,v 1.8 2005/10/03 02:18:50 drahn Exp $ */ /* $NetBSD: pte.h,v 1.1 1996/09/30 16:34:32 ws Exp $ */ /*- @@ -41,42 +41,76 @@ * Page Table Entries */ #ifndef _LOCORE -struct pte { - u_int pte_hi; - u_int pte_lo; +struct pte_32 { + u_int32_t pte_hi; + u_int32_t pte_lo; +}; +struct pte_64 { + u_int64_t pte_hi; + u_int64_t pte_lo; }; #endif /* _LOCORE */ + +/* 32 bit */ /* High word: */ -#define PTE_VALID 0x80000000 -#define PTE_VSID_SHIFT 7 -#define PTE_HID 0x00000040 -#define PTE_API 0x0000003f +#define PTE_VALID_32 0x80000000 +#define PTE_VSID_SHIFT_32 7 +#define PTE_HID_32 0x00000040 +#define PTE_API_32 0x0000003f + /* Low word: */ +#define PTE_RPGN_32 0xfffff000 +#define PTE_REF_32 0x00000100 +#define PTE_CHG_32 0x00000080 +#define PTE_WIM_32 0x00000078 +#define PTE_W_32 0x00000040 +#define PTE_EXE_32 0x00000040 /* only used in pmap_attr, same as PTE_W */ +#define PTE_I_32 0x00000020 +#define PTE_M_32 0x00000010 +#define PTE_G_32 0x00000008 +#define PTE_PP_32 0x00000003 +#define PTE_RO_32 0x00000003 +#define PTE_RW_32 0x00000002 + + +/* 64 bit */ +/* High doubleword: */ +#define PTE_VALID_64 0x0000000000000001ULL +#define PTE_AVPN_SHIFT_64 7 +#define PTE_AVPN_64 0xffffffffffffff80ULL +#define PTE_API_SHIFT_64 7 +#define PTE_API_64 0x0000000000000f80ULL +#define PTE_VSID_SHIFT_64 12 +#define PTE_VSID_64 0xfffffffffffff000ULL +#define PTE_HID_64 0x0000000000000002ULL /* Low word: */ -#define PTE_RPGN 0xfffff000 -#define PTE_REF 0x00000100 -#define PTE_CHG 0x00000080 -#define PTE_WIMG 0x00000078 -#define PTE_W 0x00000040 -#define PTE_EXE 0x00000040 /* only used in pmap_attr, same as PTE_W */ -#define PTE_I 0x00000020 -#define PTE_M 0x00000010 -#define PTE_G 0x00000008 -#define PTE_PP 0x00000003 -#define PTE_RO 0x00000003 -#define PTE_RW 0x00000002 +#define PTE_RPGN_64 0x3ffffffffffff000ULL +#define PTE_REF_64 0x0000000000000100ULL +#define PTE_CHG_64 0x0000000000000080ULL +#define PTE_WIMG_64 0x0000000000000078ULL +#define PTE_W_64 0x0000000000000040ULL +#define PTE_EXE_64 PTE_W +#define PTE_I_64 0x0000000000000020ULL +#define PTE_M_64 0x0000000000000010ULL +#define PTE_G_64 0x0000000000000008ULL +#define PTE_N_64 0x0000000000000004ULL +#define PTE_PP_64 0x0000000000000003ULL +#define PTE_RO_64 0x0000000000000003ULL +#define PTE_RW_64 0x0000000000000002ULL #ifndef _LOCORE -typedef struct pte pte_t; +typedef struct pte_32 pte32_t; +typedef struct pte_64 pte64_t; #endif /* _LOCORE */ /* * Extract bits from address */ -#define ADDR_SR_SHIFT 28 -#define ADDR_PIDX 0x0ffff000 -#define ADDR_PIDX_SHIFT 12 -#define ADDR_API_SHIFT 22 -#define ADDR_POFF 0x00000fff +#define ADDR_SR_SHIFT 28 +#define ADDR_PIDX 0x0ffff000 +#define ADDR_PIDX_SHIFT 12 +#define ADDR_API_SHIFT_32 22 +#define ADDR_API_SHIFT_64 16 +#define ADDR_POFF 0x00000fff #ifndef _LOCORE #ifdef _KERNEL diff --git a/sys/arch/powerpc/powerpc/pmap.c b/sys/arch/powerpc/powerpc/pmap.c index 0caa6e2d696..b028d1794ab 100644 --- a/sys/arch/powerpc/powerpc/pmap.c +++ b/sys/arch/powerpc/powerpc/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.89 2005/05/02 19:03:35 kettenis Exp $ */ +/* $OpenBSD: pmap.c,v 1.90 2005/10/03 02:18:50 drahn Exp $ */ /* * Copyright (c) 2001, 2002 Dale Rahn. @@ -57,10 +57,14 @@ int pmap_cnt_allocated; void * pmap_pvh; void * pmap_attrib; -struct pte *pmap_ptable; +struct pte_64 *pmap_ptable64; +struct pte_32 *pmap_ptable32; int pmap_ptab_cnt; u_int pmap_ptab_mask; -#define HTABSIZE (pmap_ptab_cnt * 64) + +#define HTABSIZE_32 (pmap_ptab_cnt * 64) +#define HTABMEMSZ_64 (pmap_ptab_cnt * 8 * sizeof(struct pte_64)) +#define HTABSIZE_64 (ffs(pmap_ptab_cnt) - 12) static u_int usedsr[NPMAPS / sizeof(u_int) / 8]; paddr_t zero_page; @@ -73,7 +77,10 @@ LIST_HEAD(pted_pv_head, pte_desc); struct pte_desc { /* Linked list of phys -> virt entries */ LIST_ENTRY(pte_desc) pted_pv_list; - struct pte pted_pte; + union { + struct pte_32 pted_pte32; + struct pte_64 pted_pte64; + }p; pmap_t pted_pmap; vaddr_t pted_va; }; @@ -82,7 +89,7 @@ void print_pteg(pmap_t pm, vaddr_t va); static inline void tlbsync(void); static inline void tlbie(vaddr_t ea); -static inline void tlbia(void); +void tlbia(void); void pmap_attr_save(paddr_t pa, u_int32_t bits); void pmap_page_ro(pmap_t pm, vaddr_t va); @@ -109,7 +116,8 @@ void pmap_remove_pv(struct pte_desc *pted); /* pte hash table routines */ -void pte_insert(struct pte_desc *pted); +void pte_insert32(struct pte_desc *pted); +void pte_insert64(struct pte_desc *pted); void pmap_hash_remove(struct pte_desc *pted); void pmap_fill_pte(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted, vm_prot_t prot, int flags, int cache); @@ -135,7 +143,7 @@ u_int32_t pmap_setusr(pmap_t pm, vaddr_t va); void pmap_popusr(u_int32_t oldsr); /* pte invalidation */ -void pte_zap(struct pte *ptp, struct pte_desc *pted); +void pte_zap(void *ptp, struct pte_desc *pted); /* debugging */ void pmap_print_pted(struct pte_desc *pted, int(*print)(const char *, ...)); @@ -315,14 +323,18 @@ tlbsync(void) __asm volatile ("sync; tlbsync; sync"); } -static inline void +void tlbia() { vaddr_t va; __asm volatile ("sync"); - for (va = 0; va < 0x00040000; va += 0x00001000) - tlbie(va); + if (ppc_proc_is_64b) + for (va = 0; va < 0x10000000; va += 0x00001000) + tlbie(va); + else + for (va = 0; va < 0x00040000; va += 0x00001000) + tlbie(va); tlbsync(); } @@ -374,7 +386,10 @@ PTED_WIRED(struct pte_desc *pted) static inline u_int32_t PTED_VALID(struct pte_desc *pted) { - return (pted->pted_pte.pte_hi & PTE_VALID); + if (ppc_proc_is_64b) + return (pted->p.pted_pte64.pte_hi & PTE_VALID_64); + else + return (pted->p.pted_pte32.pte_hi & PTE_VALID_32); } /* @@ -503,7 +518,7 @@ pmap_enter(pm, va, pa, prot, flags) if (pvh != NULL) { if (!first_map) need_sync = - (*pattr & (PTE_EXE >> ATTRSHIFT)) == 0; + (*pattr & (PTE_EXE_32 >> ATTRSHIFT)) == 0; else if (pattr != NULL) *pattr = 0; } @@ -514,7 +529,10 @@ pmap_enter(pm, va, pa, prot, flags) * We were told to map the page, probably called from vm_fault, * so map the page! */ - pte_insert(pted); + if (ppc_proc_is_64b) + pte_insert64(pted); + else + pte_insert32(pted); if (prot & VM_PROT_EXECUTE) { u_int sn = VP_SR(va); @@ -532,14 +550,14 @@ pmap_enter(pm, va, pa, prot, flags) sn << ADDR_SR_SHIFT); } if (pattr != NULL) - *pattr |= (PTE_EXE >> ATTRSHIFT); + *pattr |= (PTE_EXE_32 >> ATTRSHIFT); } else { /* * Should we be paranoid about writeable non-exec * mappings ? if so, clear the exec tag */ if ((prot & VM_PROT_WRITE) && (pattr != NULL)) - *pattr &= ~(PTE_EXE >> ATTRSHIFT); + *pattr &= ~(PTE_EXE_32 >> ATTRSHIFT); } splx(s); @@ -662,7 +680,10 @@ pmap_remove_pg(pmap_t pm, vaddr_t va) } } - pted->pted_pte.pte_hi &= ~PTE_VALID; + if (ppc_proc_is_64b) + pted->p.pted_pte64.pte_hi &= ~PTE_VALID_64; + else + pted->p.pted_pte32.pte_hi &= ~PTE_VALID_32; if (PTED_MANAGED(pted)) pmap_remove_pv(pted); @@ -727,7 +748,11 @@ _pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, int flags, int cache) * We were told to map the page, probably called from vm_fault, * so map the page! */ - pte_insert(pted); + if (ppc_proc_is_64b) + pte_insert64(pted); + else + pte_insert32(pted); + pted->pted_va |= PTED_VA_WIRED_M; if (prot & VM_PROT_EXECUTE) { @@ -815,7 +840,10 @@ pmap_kremove_pg(vaddr_t va) pmap_remove_pv(pted); /* invalidate pted; */ - pted->pted_pte.pte_hi &= ~PTE_VALID; + if (ppc_proc_is_64b) + pted->p.pted_pte64.pte_hi &= ~PTE_VALID_64; + else + pted->p.pted_pte32.pte_hi &= ~PTE_VALID_32; splx(s); @@ -831,17 +859,31 @@ pmap_kremove(vaddr_t va, vsize_t len) } void -pte_zap(struct pte *ptp, struct pte_desc *pted) +pte_zap(void *ptp, struct pte_desc *pted) { - ptp->pte_hi &= ~PTE_VALID; - __asm volatile ("sync"); - tlbie(pted->pted_va); - __asm volatile ("sync"); - tlbsync(); - __asm volatile ("sync"); + + struct pte_64 *ptp64 = (void*) ptp; + struct pte_32 *ptp32 = (void*) ptp; + + if (ppc_proc_is_64b) + ptp64->pte_hi &= ~PTE_VALID_64; + else + ptp32->pte_hi &= ~PTE_VALID_32; + + __asm volatile ("sync"); + tlbie(pted->pted_va); + __asm volatile ("sync"); + tlbsync(); + __asm volatile ("sync"); + if (ppc_proc_is_64b) { if (PTED_MANAGED(pted)) - pmap_attr_save(pted->pted_pte.pte_lo & PTE_RPGN, - ptp->pte_lo & (PTE_REF|PTE_CHG)); + pmap_attr_save(pted->p.pted_pte64.pte_lo & PTE_RPGN_64, + ptp64->pte_lo & (PTE_REF_64|PTE_CHG_64)); + } else { + if (PTED_MANAGED(pted)) + pmap_attr_save(pted->p.pted_pte32.pte_lo & PTE_RPGN_32, + ptp32->pte_lo & (PTE_REF_32|PTE_CHG_32)); + } } /* @@ -854,7 +896,8 @@ pmap_hash_remove(struct pte_desc *pted) { vaddr_t va = pted->pted_va; pmap_t pm = pted->pted_pmap; - struct pte *ptp; + struct pte_64 *ptp64; + struct pte_32 *ptp32; int sr, idx; sr = ptesr(pm->pm_sr, va); @@ -862,17 +905,33 @@ pmap_hash_remove(struct pte_desc *pted) idx = (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)); /* determine which pteg mapping is present in */ - ptp = pmap_ptable + (idx * 8); - ptp += PTED_PTEGIDX(pted); /* increment by index into pteg */ - /* - * We now have the pointer to where it will be, if it is currently - * mapped. If the mapping was thrown away in exchange for another - * page mapping, then this page is not currently in the HASH. - */ - if ((pted->pted_pte.pte_hi | (PTED_HID(pted) ? PTE_HID : 0)) - == ptp->pte_hi) { - pte_zap(ptp, pted); + if (ppc_proc_is_64b) { + ptp64 = pmap_ptable64 + (idx * 8); + ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + /* + * We now have the pointer to where it will be, if it is + * currently mapped. If the mapping was thrown away in + * exchange for another page mapping, then this page is not + * currently in the HASH. + */ + if ((pted->p.pted_pte64.pte_hi | + (PTED_HID(pted) ? PTE_HID_64 : 0)) == ptp64->pte_hi) { + pte_zap((void*)ptp64, pted); + } + } else { + ptp32 = pmap_ptable32 + (idx * 8); + ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + /* + * We now have the pointer to where it will be, if it is + * currently mapped. If the mapping was thrown away in + * exchange for another page mapping, then this page is not + * currently in the HASH. + */ + if ((pted->p.pted_pte32.pte_hi | + (PTED_HID(pted) ? PTE_HID_32 : 0)) == ptp32->pte_hi) { + pte_zap((void*)ptp32, pted); + } } } @@ -884,29 +943,54 @@ pmap_fill_pte(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted, vm_prot_t prot, int flags, int cache) { sr_t sr; - struct pte *pte; + struct pte_32 *pte32; + struct pte_64 *pte64; sr = ptesr(pm->pm_sr, va); - pte = &pted->pted_pte; - pte->pte_hi = ((sr & SR_VSID) << PTE_VSID_SHIFT) | - ((va >> ADDR_API_SHIFT) & PTE_API) | PTE_VALID; - pte->pte_lo = (pa & PTE_RPGN); + if (ppc_proc_is_64b) { + pte64 = &pted->p.pted_pte64; + pte64->pte_hi = (((u_int64_t)sr & SR_VSID) << + PTE_VSID_SHIFT_64) | + ((va >> ADDR_API_SHIFT_64) & PTE_API_64) | PTE_VALID_64; + pte64->pte_lo = (pa & PTE_RPGN_64); - if ((cache == PMAP_CACHE_WB)) - pte->pte_lo |= PTE_M; - else if ((cache == PMAP_CACHE_WT)) - pte->pte_lo |= (PTE_W | PTE_M); - else - pte->pte_lo |= (PTE_M | PTE_I | PTE_G); - if (prot & VM_PROT_WRITE) - pte->pte_lo |= PTE_RW; - else - pte->pte_lo |= PTE_RO; + if ((cache == PMAP_CACHE_WB)) + pte64->pte_lo |= PTE_M_64; + else if ((cache == PMAP_CACHE_WT)) + pte64->pte_lo |= (PTE_W_64 | PTE_M_64); + else + pte64->pte_lo |= (PTE_M_64 | PTE_I_64 | PTE_G_64); + + if (prot & VM_PROT_WRITE) + pte64->pte_lo |= PTE_RW_64; + else + pte64->pte_lo |= PTE_RO_64; + } else { + pte32 = &pted->p.pted_pte32; + + pte32->pte_hi = ((sr & SR_VSID) << PTE_VSID_SHIFT_32) | + ((va >> ADDR_API_SHIFT_32) & PTE_API_32) | PTE_VALID_32; + pte32->pte_lo = (pa & PTE_RPGN_32); + + + if ((cache == PMAP_CACHE_WB)) + pte32->pte_lo |= PTE_M_32; + else if ((cache == PMAP_CACHE_WT)) + pte32->pte_lo |= (PTE_W_32 | PTE_M_32); + else + pte32->pte_lo |= (PTE_M_32 | PTE_I_32 | PTE_G_32); + + if (prot & VM_PROT_WRITE) + pte32->pte_lo |= PTE_RW_32; + else + pte32->pte_lo |= PTE_RO_32; + } pted->pted_va = va & ~PAGE_MASK; + /* XXX Per-page execution control. */ if (prot & VM_PROT_EXECUTE) pted->pted_va |= PTED_VA_EXEC_M; @@ -926,6 +1010,9 @@ pteclrbits(paddr_t pa, u_int bit, u_int clear) struct pte_desc *pted; struct pted_pv_head *pvh; + /* PTE_CHG_32 == PTE_CHG_64 */ + /* PTE_REG_32 == PTE_REG_64 */ + pattr = pmap_find_attr(pa); /* check if managed memory */ @@ -952,39 +1039,70 @@ pteclrbits(paddr_t pa, u_int bit, u_int clear) LIST_FOREACH(pted, pvh, pted_pv_list) { vaddr_t va = pted->pted_va & PAGE_MASK; pmap_t pm = pted->pted_pmap; - struct pte *ptp; + struct pte_64 *ptp64; + struct pte_32 *ptp32; int sr, idx; sr = ptesr(pm->pm_sr, va); idx = pteidx(sr, va); /* determine which pteg mapping is present in */ - ptp = pmap_ptable + - (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; - ptp += PTED_PTEGIDX(pted); /* increment by index into pteg */ - - /* - * We now have the pointer to where it will be, if it is - * currently mapped. If the mapping was thrown away in - * exchange for another page mapping, then this page is - * not currently in the HASH. - * - * if we are not clearing bits, and have found all of the - * bits we want, we can stop - */ - if ((pted->pted_pte.pte_hi | (PTED_HID(pted) ? PTE_HID : 0)) - == ptp->pte_hi) { - bits |= ptp->pte_lo & bit; - if (clear) { - ptp->pte_hi &= ~PTE_VALID; - __asm__ volatile ("sync"); - tlbie(va); - tlbsync(); - ptp->pte_lo &= ~bit; - __asm__ volatile ("sync"); - ptp->pte_hi |= PTE_VALID; - } else if (bits == bit) - break; + if (ppc_proc_is_64b) { + ptp64 = pmap_ptable64 + + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; + ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + + /* + * We now have the pointer to where it will be, if it is + * currently mapped. If the mapping was thrown away in + * exchange for another page mapping, then this page is + * not currently in the HASH. + * + * if we are not clearing bits, and have found all of the + * bits we want, we can stop + */ + if ((pted->p.pted_pte64.pte_hi | + (PTED_HID(pted) ? PTE_HID_64 : 0)) == ptp64->pte_hi) { + bits |= ptp64->pte_lo & bit; + if (clear) { + ptp64->pte_hi &= ~PTE_VALID_64; + __asm__ volatile ("sync"); + tlbie(va); + tlbsync(); + ptp64->pte_lo &= ~bit; + __asm__ volatile ("sync"); + ptp64->pte_hi |= PTE_VALID_64; + } else if (bits == bit) + break; + } + } else { + ptp32 = pmap_ptable32 + + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; + ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + + /* + * We now have the pointer to where it will be, if it is + * currently mapped. If the mapping was thrown away in + * exchange for another page mapping, then this page is + * not currently in the HASH. + * + * if we are not clearing bits, and have found all of the + * bits we want, we can stop + */ + if ((pted->p.pted_pte32.pte_hi | + (PTED_HID(pted) ? PTE_HID_32 : 0)) == ptp32->pte_hi) { + bits |= ptp32->pte_lo & bit; + if (clear) { + ptp32->pte_hi &= ~PTE_VALID_32; + __asm__ volatile ("sync"); + tlbie(va); + tlbsync(); + ptp32->pte_lo &= ~bit; + __asm__ volatile ("sync"); + ptp32->pte_hi |= PTE_VALID_32; + } else if (bits == bit) + break; + } } } @@ -1394,6 +1512,8 @@ pmap_bootstrap(u_int kernelstart, u_int kernelend) struct pmapvp *vp1; struct pmapvp *vp2; + ppc_check_procid(); + /* * Get memory. */ @@ -1414,19 +1534,30 @@ pmap_bootstrap(u_int kernelstart, u_int kernelend) bzero((void *)mp->start, mp->size); } -#ifndef HTABENTS -#define HTABENTS 1024 -#endif - pmap_ptab_cnt = HTABENTS; - while ((HTABSIZE << 7) < ctob(physmem)) { - pmap_ptab_cnt <<= 1; +#define HTABENTS_32 1024 +#define HTABENTS_64 2048 + + if (ppc_proc_is_64b) { + pmap_ptab_cnt = HTABENTS_64; + while (pmap_ptab_cnt * 2 < physmem) + pmap_ptab_cnt <<= 1; + } else { + pmap_ptab_cnt = HTABENTS_32; + while ((HTABSIZE_32 << 7) < ctob(physmem)) + pmap_ptab_cnt <<= 1; } /* * allocate suitably aligned memory for HTAB */ - pmap_ptable = pmap_steal_avail(HTABSIZE, HTABSIZE); - bzero((void *)pmap_ptable, HTABSIZE); - pmap_ptab_mask = pmap_ptab_cnt - 1; + if (ppc_proc_is_64b) { + pmap_ptable64 = pmap_steal_avail(HTABMEMSZ_64, HTABMEMSZ_64); + bzero((void *)pmap_ptable64, HTABMEMSZ_64); + pmap_ptab_mask = pmap_ptab_cnt - 1; + } else { + pmap_ptable32 = pmap_steal_avail(HTABSIZE_32, HTABSIZE_32); + bzero((void *)pmap_ptable32, HTABSIZE_32); + pmap_ptab_mask = pmap_ptab_cnt - 1; + } /* allocate v->p mappings for pmap_kernel() */ for (i = 0; i < VP_SR_SIZE; i++) { @@ -1435,7 +1566,6 @@ pmap_bootstrap(u_int kernelstart, u_int kernelend) vp1 = pmap_steal_avail(sizeof (struct pmapvp), 4); bzero (vp1, sizeof(struct pmapvp)); pmap_kernel()->pm_vp[PPC_KERNEL_SR] = vp1; - for (i = 0; i < VP_IDX1_SIZE; i++) { vp2 = vp1->vp[i] = pmap_steal_avail(sizeof (struct pmapvp), 4); bzero (vp2, sizeof(struct pmapvp)); @@ -1447,6 +1577,23 @@ pmap_bootstrap(u_int kernelstart, u_int kernelend) } } + if (ppc_proc_is_64b) { + vp1 = pmap_steal_avail(sizeof (struct pmapvp), 4); + bzero (vp1, sizeof(struct pmapvp)); + pmap_kernel()->pm_vp[0] = vp1; + for (i = 0; i < VP_IDX1_SIZE; i++) { + vp2 = vp1->vp[i] = + pmap_steal_avail(sizeof (struct pmapvp), 4); + bzero (vp2, sizeof(struct pmapvp)); + for (k = 0; k < VP_IDX2_SIZE; k++) { + struct pte_desc *pted; + pted = pmap_steal_avail(sizeof (struct pte_desc), 4); + bzero (pted, sizeof (struct pte_desc)); + vp2->vp[k] = pted; + } + } + } + zero_page = VM_MIN_KERNEL_ADDRESS + ppc_kvm_stolen; ppc_kvm_stolen += PAGE_SIZE; copy_src_page = VM_MIN_KERNEL_ADDRESS + ppc_kvm_stolen; @@ -1466,8 +1613,16 @@ pmap_bootstrap(u_int kernelstart, u_int kernelend) pmap_kernel()->pm_sr[i] = (PPC_KERNEL_SEG0 + i) | SR_NOEXEC; ppc_mtsrin(PPC_KERNEL_SEG0 + i, i << ADDR_SR_SHIFT); } - asm volatile ("sync; mtsdr1 %0; isync" - :: "r"((u_int)pmap_ptable | (pmap_ptab_mask >> 10))); + + if (ppc_proc_is_64b) { + for(i = 0; i < 0x10000; i++) + pmap_kenter_cache(ctob(i), ctob(i), VM_PROT_ALL, + PMAP_CACHE_WB); + asm volatile ("sync; mtsdr1 %0; isync" + :: "r"((u_int)pmap_ptable64 | HTABSIZE_64)); + } else + asm volatile ("sync; mtsdr1 %0; isync" + :: "r"((u_int)pmap_ptable32 | (pmap_ptab_mask >> 10))); pmap_avail_fixup(); @@ -1528,7 +1683,12 @@ pmap_extract(pmap_t pm, vaddr_t va, paddr_t *pa) } return FALSE; } - *pa = (pted->pted_pte.pte_lo & PTE_RPGN) | (va & ~PTE_RPGN); + if (ppc_proc_is_64b) + *pa = (pted->p.pted_pte64.pte_lo & PTE_RPGN_64) | + (va & ~PTE_RPGN_64); + else + *pa = (pted->p.pted_pte32.pte_lo & PTE_RPGN_32) | + (va & ~PTE_RPGN_32); return TRUE; } @@ -1782,7 +1942,8 @@ pmap_syncicache_user_virt(pmap_t pm, vaddr_t va) void pmap_page_ro(pmap_t pm, vaddr_t va) { - struct pte *ptp; + struct pte_64 *ptp64; + struct pte_32 *ptp32; struct pte_desc *pted; int sr, idx; @@ -1790,37 +1951,73 @@ pmap_page_ro(pmap_t pm, vaddr_t va) if (pted == NULL || !PTED_VALID(pted)) return; - pted->pted_pte.pte_lo &= ~PTE_PP; - pted->pted_pte.pte_lo |= PTE_RO; + if (ppc_proc_is_64b) { + pted->p.pted_pte64.pte_lo &= ~PTE_PP_64; + pted->p.pted_pte64.pte_lo |= PTE_RO_64; + } else { + pted->p.pted_pte32.pte_lo &= ~PTE_PP_32; + pted->p.pted_pte32.pte_lo |= PTE_RO_32; + } sr = ptesr(pm->pm_sr, va); idx = pteidx(sr, va); - /* determine which pteg mapping is present in */ - ptp = pmap_ptable + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; - ptp += PTED_PTEGIDX(pted); /* increment by index into pteg */ + if (ppc_proc_is_64b) { + /* determine which pteg mapping is present in */ + ptp64 = pmap_ptable64 + + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; + ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */ - /* - * We now have the pointer to where it will be, if it is - * currently mapped. If the mapping was thrown away in - * exchange for another page mapping, then this page is - * not currently in the HASH. - */ - if ((pted->pted_pte.pte_hi | (PTED_HID(pted) ? PTE_HID : 0)) - == ptp->pte_hi) { - ptp->pte_hi &= ~PTE_VALID; - __asm__ volatile ("sync"); - tlbie(va); - tlbsync(); - if (PTED_MANAGED(pted)) { /* XXX */ - pmap_attr_save(ptp->pte_lo & PTE_RPGN, - ptp->pte_lo & (PTE_REF|PTE_CHG)); + /* + * We now have the pointer to where it will be, if it is + * currently mapped. If the mapping was thrown away in + * exchange for another page mapping, then this page is + * not currently in the HASH. + */ + if ((pted->p.pted_pte64.pte_hi | (PTED_HID(pted) ? PTE_HID_64 : 0)) + == ptp64->pte_hi) { + ptp64->pte_hi &= ~PTE_VALID_64; + __asm__ volatile ("sync"); + tlbie(va); + tlbsync(); + if (PTED_MANAGED(pted)) { /* XXX */ + pmap_attr_save(ptp64->pte_lo & PTE_RPGN_64, + ptp64->pte_lo & (PTE_REF_64|PTE_CHG_64)); + } + ptp64->pte_lo &= ~PTE_CHG_64; + ptp64->pte_lo &= ~PTE_PP_64; + ptp64->pte_lo |= PTE_RO_64; + __asm__ volatile ("sync"); + ptp64->pte_hi |= PTE_VALID_64; + } + } else { + /* determine which pteg mapping is present in */ + ptp32 = pmap_ptable32 + + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; + ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + + /* + * We now have the pointer to where it will be, if it is + * currently mapped. If the mapping was thrown away in + * exchange for another page mapping, then this page is + * not currently in the HASH. + */ + if ((pted->p.pted_pte32.pte_hi | (PTED_HID(pted) ? PTE_HID_32 : 0)) + == ptp32->pte_hi) { + ptp32->pte_hi &= ~PTE_VALID_32; + __asm__ volatile ("sync"); + tlbie(va); + tlbsync(); + if (PTED_MANAGED(pted)) { /* XXX */ + pmap_attr_save(ptp32->pte_lo & PTE_RPGN_32, + ptp32->pte_lo & (PTE_REF_32|PTE_CHG_32)); + } + ptp32->pte_lo &= ~PTE_CHG_32; + ptp32->pte_lo &= ~PTE_PP_32; + ptp32->pte_lo |= PTE_RO_32; + __asm__ volatile ("sync"); + ptp32->pte_hi |= PTE_VALID_32; } - ptp->pte_lo &= ~PTE_CHG; - ptp->pte_lo &= ~PTE_PP; - ptp->pte_lo |= PTE_RO; - __asm__ volatile ("sync"); - ptp->pte_hi |= PTE_VALID; } } @@ -2006,16 +2203,27 @@ pte_spill_r(u_int32_t va, u_int32_t msr, u_int32_t dsisr, int exec_fault) if (!PTED_VALID(pted)) { return 0; } - if ((dsisr & (1 << (31-6))) && (pted->pted_pte.pte_lo & 0x1)) { - /* write fault and we have a readonly mapping */ - return 0; + + if (ppc_proc_is_64b) { + /* check write fault and we have a readonly mapping */ + if ((dsisr & (1 << (31-6))) && + (pted->p.pted_pte64.pte_lo & 0x1)) + return 0; + } else { + /* check write fault and we have a readonly mapping */ + if ((dsisr & (1 << (31-6))) && + (pted->p.pted_pte32.pte_lo & 0x1)) + return 0; } if ((exec_fault != 0) && ((pted->pted_va & PTED_VA_EXEC_M) == 0)) { /* attempted to execute non-executable page */ return 0; } - pte_insert(pted); + if (ppc_proc_is_64b) + pte_insert64(pted); + else + pte_insert32(pted); return 1; } @@ -2037,16 +2245,26 @@ pte_spill_v(pmap_t pm, u_int32_t va, u_int32_t dsisr, int exec_fault) if (!PTED_VALID(pted)) { return 0; } - if ((dsisr & (1 << (31-6))) && (pted->pted_pte.pte_lo & 0x1)) { - /* write fault and we have a readonly mapping */ - return 0; + if (ppc_proc_is_64b) { + /* check write fault and we have a readonly mapping */ + if ((dsisr & (1 << (31-6))) && + (pted->p.pted_pte64.pte_lo & 0x1)) + return 0; + } else { + /* check write fault and we have a readonly mapping */ + if ((dsisr & (1 << (31-6))) && + (pted->p.pted_pte32.pte_lo & 0x1)) + return 0; } if ((exec_fault != 0) && ((pted->pted_va & PTED_VA_EXEC_M) == 0)) { /* attempted to execute non-executable page */ return 0; } - pte_insert(pted); + if (ppc_proc_is_64b) + pte_insert64(pted); + else + pte_insert32(pted); return 1; } @@ -2057,13 +2275,118 @@ pte_spill_v(pmap_t pm, u_int32_t va, u_int32_t dsisr, int exec_fault) * is the pted safe? (physical) * -ugh */ +void +pte_insert64(struct pte_desc *pted) +{ + int off; + int secondary; + struct pte_64 *ptp64; + int sr, idx; + int i; + + /* HASH lock? */ + + sr = ptesr(pted->pted_pmap->pm_sr, pted->pted_va); + idx = pteidx(sr, pted->pted_va); + + ptp64 = pmap_ptable64 + + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; + ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + if ((pted->p.pted_pte64.pte_hi | + (PTED_HID(pted) ? PTE_HID_64 : 0)) == ptp64->pte_hi) + pte_zap(ptp64,pted); + + pted->pted_va &= ~(PTED_VA_HID_M|PTED_VA_PTEGIDX_M); + + /* + * instead of starting at the beginning of each pteg, + * the code should pick a random location with in the primary + * then search all of the entries, then if not yet found, + * do the same for the secondary. + * this would reduce the frontloading of the pteg. + */ + /* first just try fill of primary hash */ + ptp64 = pmap_ptable64 + (idx) * 8; + for (i = 0; i < 8; i++) { + if (ptp64[i].pte_hi & PTE_VALID_64) + continue; + + /* not valid, just load */ + pted->pted_va |= i; + ptp64[i].pte_hi = + pted->p.pted_pte64.pte_hi & ~PTE_VALID_64; + ptp64[i].pte_lo = pted->p.pted_pte64.pte_lo; + __asm__ volatile ("sync"); + ptp64[i].pte_hi |= PTE_VALID_64; + __asm volatile ("sync"); + return; + } + /* first just try fill of secondary hash */ + ptp64 = pmap_ptable64 + (idx ^ pmap_ptab_mask) * 8; + for (i = 0; i < 8; i++) { + if (ptp64[i].pte_hi & PTE_VALID_64) + continue; + + pted->pted_va |= (i | PTED_VA_HID_M); + ptp64[i].pte_hi = + (pted->p.pted_pte64.pte_hi | PTE_HID_64) & ~PTE_VALID_64; + ptp64[i].pte_lo = pted->p.pted_pte64.pte_lo; + __asm__ volatile ("sync"); + ptp64[i].pte_hi |= PTE_VALID_64; + __asm volatile ("sync"); + return; + } + + /* need decent replacement algorithm */ + __asm__ volatile ("mftb %0" : "=r"(off)); + secondary = off & 8; + pted->pted_va |= off & (PTED_VA_PTEGIDX_M|PTED_VA_HID_M); + + idx = (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)); + + ptp64 = pmap_ptable64 + (idx * 8); + ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + if (ptp64->pte_hi & PTE_VALID_64) { + vaddr_t va; + ptp64->pte_hi &= ~PTE_VALID_64; + __asm volatile ("sync"); + + /* Bits 9-19 */ + idx = (idx ^ ((ptp64->pte_hi & PTE_HID_64) ? + pmap_ptab_mask : 0)); + va = (ptp64->pte_hi >> PTE_VSID_SHIFT_64) ^ idx; + va <<= ADDR_PIDX_SHIFT; + /* Bits 4-8 */ + va |= (ptp64->pte_hi & PTE_API_64) << ADDR_API_SHIFT_32; + /* Bits 0-3 */ + va |= (ptp64->pte_hi >> PTE_VSID_SHIFT_64) + << ADDR_SR_SHIFT; + tlbie(va); + + tlbsync(); + pmap_attr_save(ptp64->pte_lo & PTE_RPGN_64, + ptp64->pte_lo & (PTE_REF_32|PTE_CHG_32)); + } + + if (secondary) + ptp64->pte_hi = + (pted->p.pted_pte64.pte_hi | PTE_HID_64) & + ~PTE_VALID_64; + else + ptp64->pte_hi = pted->p.pted_pte64.pte_hi & + ~PTE_VALID_64; + + ptp64->pte_lo = pted->p.pted_pte64.pte_lo; + __asm__ volatile ("sync"); + ptp64->pte_hi |= PTE_VALID_64; +} void -pte_insert(struct pte_desc *pted) +pte_insert32(struct pte_desc *pted) { int off; int secondary; - struct pte *ptp; + struct pte_32 *ptp32; int sr, idx; int i; @@ -2073,12 +2396,12 @@ pte_insert(struct pte_desc *pted) idx = pteidx(sr, pted->pted_va); /* determine if ptp is already mapped */ - ptp = pmap_ptable + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; - ptp += PTED_PTEGIDX(pted); /* increment by index into pteg */ - if ((pted->pted_pte.pte_hi | (PTED_HID(pted) ? PTE_HID : 0)) - == ptp->pte_hi) { - pte_zap(ptp,pted); - } + ptp32 = pmap_ptable32 + + (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8; + ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + if ((pted->p.pted_pte32.pte_hi | + (PTED_HID(pted) ? PTE_HID_32 : 0)) == ptp32->pte_hi) + pte_zap(ptp32,pted); pted->pted_va &= ~(PTED_VA_HID_M|PTED_VA_PTEGIDX_M); @@ -2091,32 +2414,32 @@ pte_insert(struct pte_desc *pted) */ /* first just try fill of primary hash */ - ptp = pmap_ptable + (idx) * 8; + ptp32 = pmap_ptable32 + (idx) * 8; for (i = 0; i < 8; i++) { - if (ptp[i].pte_hi & PTE_VALID) + if (ptp32[i].pte_hi & PTE_VALID_32) continue; /* not valid, just load */ -/* printf("inserting in primary idx %x, i %x\n", idx, i); */ pted->pted_va |= i; - ptp[i].pte_hi = pted->pted_pte.pte_hi & ~PTE_VALID; - ptp[i].pte_lo = pted->pted_pte.pte_lo; + ptp32[i].pte_hi = pted->p.pted_pte32.pte_hi & ~PTE_VALID_32; + ptp32[i].pte_lo = pted->p.pted_pte32.pte_lo; __asm__ volatile ("sync"); - ptp[i].pte_hi |= PTE_VALID; + ptp32[i].pte_hi |= PTE_VALID_32; __asm volatile ("sync"); return; } /* first just try fill of secondary hash */ - ptp = pmap_ptable + (idx ^ pmap_ptab_mask) * 8; + ptp32 = pmap_ptable32 + (idx ^ pmap_ptab_mask) * 8; for (i = 0; i < 8; i++) { - if (ptp[i].pte_hi & PTE_VALID) + if (ptp32[i].pte_hi & PTE_VALID_32) continue; pted->pted_va |= (i | PTED_VA_HID_M); - ptp[i].pte_hi = (pted->pted_pte.pte_hi | PTE_HID) & ~PTE_VALID; - ptp[i].pte_lo = pted->pted_pte.pte_lo; + ptp32[i].pte_hi = + (pted->p.pted_pte32.pte_hi | PTE_HID_32) & ~PTE_VALID_32; + ptp32[i].pte_lo = pted->p.pted_pte32.pte_lo; __asm__ volatile ("sync"); - ptp[i].pte_hi |= PTE_VALID; + ptp32[i].pte_hi |= PTE_VALID_32; __asm volatile ("sync"); return; } @@ -2126,34 +2449,34 @@ pte_insert(struct pte_desc *pted) secondary = off & 8; pted->pted_va |= off & (PTED_VA_PTEGIDX_M|PTED_VA_HID_M); - idx = (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)); + idx = (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)); - ptp = pmap_ptable + (idx * 8); - ptp += PTED_PTEGIDX(pted); /* increment by index into pteg */ - if (ptp->pte_hi & PTE_VALID) { + ptp32 = pmap_ptable32 + (idx * 8); + ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */ + if (ptp32->pte_hi & PTE_VALID_32) { vaddr_t va; - ptp->pte_hi &= ~PTE_VALID; + ptp32->pte_hi &= ~PTE_VALID_32; __asm volatile ("sync"); - va = ((ptp->pte_hi & PTE_API) << ADDR_API_SHIFT) | - ((((ptp->pte_hi >> PTE_VSID_SHIFT) & SR_VSID) - ^(idx ^ ((ptp->pte_hi & PTE_HID) ? 0x3ff : 0))) + va = ((ptp32->pte_hi & PTE_API_32) << ADDR_API_SHIFT_32) | + ((((ptp32->pte_hi >> PTE_VSID_SHIFT_32) & SR_VSID) + ^(idx ^ ((ptp32->pte_hi & PTE_HID_32) ? 0x3ff : 0))) & 0x3ff) << PAGE_SHIFT; tlbie(va); tlbsync(); - pmap_attr_save(ptp->pte_lo & PTE_RPGN, - ptp->pte_lo & (PTE_REF|PTE_CHG)); + pmap_attr_save(ptp32->pte_lo & PTE_RPGN_32, + ptp32->pte_lo & (PTE_REF_32|PTE_CHG_32)); } - if (secondary) - ptp->pte_hi = (pted->pted_pte.pte_hi | PTE_HID) & ~PTE_VALID; + ptp32->pte_hi = + (pted->p.pted_pte32.pte_hi | PTE_HID_32) & ~PTE_VALID_32; else - ptp->pte_hi = pted->pted_pte.pte_hi & ~PTE_VALID; - - ptp->pte_lo = pted->pted_pte.pte_lo; + ptp32->pte_hi = pted->p.pted_pte32.pte_hi & ~PTE_VALID_32; + ptp32->pte_lo = pted->p.pted_pte32.pte_lo; __asm__ volatile ("sync"); - ptp->pte_hi |= PTE_VALID; + ptp32->pte_hi |= PTE_VALID_32; + } #ifdef DEBUG_PMAP @@ -2200,14 +2523,27 @@ pmap_print_pted(struct pte_desc *pted, int(*print)(const char *, ...)) print(" PTEGIDX %x", PTED_PTEGIDX(pted)); print(" MANAGED %d", PTED_MANAGED(pted) ? 1: 0); print(" WIRED %d\n", PTED_WIRED(pted) ? 1: 0); - print("ptehi %x ptelo %x ptp %x Aptp %x\n", - pted->pted_pte.pte_hi, pted->pted_pte.pte_lo, - pmap_ptable + - 8*pteidx(ptesr(pted->pted_pmap->pm_sr, va), va), - pmap_ptable + - 8*(pteidx(ptesr(pted->pted_pmap->pm_sr, va), va) - ^ pmap_ptab_mask) - ); + if (ppc_proc_is_64b) { + print("ptehi %x ptelo %x ptp %x Aptp %x\n", + pted->p.pted_pte64.pte_hi, + pted->p.pted_pte64.pte_lo, + pmap_ptable + + 8*pteidx(ptesr(pted->pted_pmap->pm_sr, va), va), + pmap_ptable + + 8*(pteidx(ptesr(pted->pted_pmap->pm_sr, va), va) + ^ pmap_ptab_mask) + ); + } else { + print("ptehi %x ptelo %x ptp %x Aptp %x\n", + pted->p.pted_pte32.pte_hi, + pted->p.pted_pte32.pte_lo, + pmap_ptable + + 8*pteidx(ptesr(pted->pted_pmap->pm_sr, va), va), + pmap_ptable + + 8*(pteidx(ptesr(pted->pted_pmap->pm_sr, va), va) + ^ pmap_ptab_mask) + ); + } } } |