📄 hashtable.s
字号:
/* * arch/ppc/kernel/hashtable.S * * $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> * Adapted for Power Macintosh by Paul Mackerras. * Low-level exception handlers and MMU support * rewritten by Paul Mackerras. * Copyright (C) 1996 Paul Mackerras. * * This file contains low-level assembler routines for managing * the PowerPC MMU hash table. (PPC 8xx processors don't use a * hash table, so this file is not used on them.) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */#include "ppc_asm.h"#include <asm/processor.h>#include <asm/page.h>#include <linux/config.h>#include "mol.h"/* * Load a PTE into the hash table, if possible. * The address is in r3, and r4 contains access flags: * _PAGE_USER (4) if a user-mode access, ored with * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1, * so bit 1 (0x40000000) is set if the exception was due * to no matching PTE being found in the hash table. * SPRG3 contains the physical address of the current task's thread. * * Returns to the caller if the access is illegal or there is no * mapping for the address. Otherwise it places an appropriate PTE * in the hash table and returns from the exception. * Uses r0, r2 - r6, ctr, lr. * * For speed, 4 of the instructions get patched once the size and * physical address of the hash table are known. These definitions * of Hash_base and Hash_bits below are just an example. */Hash_base = 0x180000Hash_bits = 12 /* e.g. 256kB hash table */Hash_msk = (((1 << Hash_bits) - 1) * 64) .globl hash_pagehash_page:#ifdef CONFIG_PPC64BRIDGE mfmsr r0 clrldi r0,r0,1 /* make sure it's in 32-bit mode */ sync MTMSRD(r0) isync#endif#ifdef CONFIG_SMP SAVE_2GPRS(7,r21) eieio lis r2,hash_table_lock@h ori r2,r2,hash_table_lock@l tophys(r2,r2) lis r6,0x0fff0000@h mtctr r6 mfspr r5,SPRG3 lwz r0,PROCESSOR-THREAD(r5) or r0,r0,r610: lwarx r6,0,r2 cmpi 0,r6,0 bne- 12f stwcx. r0,0,r2 beq+ 11f /* spin here a bit */12: mfctr r7 li r8,1000 mtctr r813: bdnz 13b mtctr r7 cmpw r6,r0 bdnzf 2,10b tw 31,31,3111: eieio REST_2GPRS(7, r21)#endif /* Get PTE (linux-style) and check access */ lis r0,KERNELBASE@h /* check if kernel address */ cmplw 0,r3,r0 mfspr r2,SPRG3 /* current task's THREAD (phys) */ lwz r5,PGDIR(r2) /* virt page-table root */ blt+ 112f /* assume user more likely */ lis r5,swapper_pg_dir@ha /* if kernel address, use */ addi r5,r5,swapper_pg_dir@l /* kernel page table */112: tophys(r5,r5) /* convert to phys addr */ rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */ lwz r5,0(r5) /* get pmd entry */ rlwinm. r5,r5,0,0,19 /* extract address of pte page */#ifdef CONFIG_SMP beq- hash_page_out /* return if no mapping */#else /* XXX it seems like the 601 will give a machine fault on the rfi if its alignment is wrong (bottom 4 bits of address are 8 or 0xc) and we have had a not-taken conditional branch to the address following the rfi. */ beqlr-#endif tophys(r2,r5) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r6,0(r2) /* get linux-style pte */ ori r4,r4,1 /* set _PAGE_PRESENT bit in access */ andc. r0,r4,r6 /* check access & ~permission */#ifdef CONFIG_SMP bne- hash_page_out /* return if access not permitted */#else bnelr-#endif ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */ rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */ or r6,r6,r5 stw r6,0(r2) /* update PTE (accessed/dirty bits) */ /* Convert linux-style PTE to low word of PPC-style PTE */ rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ ori r4,r4,0xe04 /* clear out reserved bits */ andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */#ifdef CONFIG_POWER4 /* * XXX hack hack hack - translate 32-bit "physical" addresses * in the linux page tables to 42-bit real addresses in such * a fashion that we can get at the I/O we need to access. * -- paulus */ cmpwi 0,r6,0 rlwinm r4,r6,16,16,30 bge 57f cmplwi 0,r4,0xfe00 li r5,0x3fd bne 56f li r5,0x3ff56: sldi r5,r5,32 or r6,r6,r557:#endif#ifdef CONFIG_PPC64BRIDGE /* Construct the high word of the PPC-style PTE */ mfsrin r5,r3 /* get segment reg for segment */ rlwinm r5,r5,0,5,31 sldi r5,r5,12 ori r5,r5,1 /* set V (valid) bit */ rlwimi r5,r3,16,20,24 /* put in API (abbrev page index) */ /* Get the address of the primary PTE group in the hash table */ .globl hash_page_patch_Ahash_page_patch_A: lis r4,Hash_base@h /* base address of hash table */ rlwimi r4,r5,32-5,25-Hash_bits,24 /* (VSID & hash_mask) << 7 */ rlwinm r0,r3,32-5,25-Hash_bits,24 /* (PI & hash_mask) << 7 */ xor r4,r4,r0 /* make primary hash */ /* See whether it was a PTE not found exception or a protection violation. */ andis. r0,r20,0x4000 li r2,8 /* PTEs/group */ bne 10f /* no PTE: go look for an empty slot */ tlbie r3 /* invalidate TLB entry */ /* Search the primary PTEG for a PTE whose 1st dword matches r5 */ mtctr r2 addi r3,r4,-161: ldu r0,16(r3) /* get next PTE */ cmpd 0,r0,r5 bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_slot /* Search the secondary PTEG for a matching PTE */ ori r5,r5,0x2 /* set H (secondary hash) bit */ .globl hash_page_patch_Bhash_page_patch_B: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xff80 addi r3,r3,-16 mtctr r22: ldu r0,16(r3) cmpd 0,r0,r5 bdnzf 2,2b beq+ found_slot xori r5,r5,0x2 /* clear H bit again */ /* Search the primary PTEG for an empty slot */10: mtctr r2 addi r3,r4,-16 /* search primary PTEG */1: ldu r0,16(r3) /* get next PTE */ andi. r0,r0,1 bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_empty /* Search the secondary PTEG for an empty slot */ ori r5,r5,0x2 /* set H (secondary hash) bit */ .globl hash_page_patch_Chash_page_patch_C: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xff80 addi r3,r3,-16 mtctr r22: ldu r0,16(r3) andi. r0,r0,1 bdnzf 2,2b beq+ found_empty /* * Choose an arbitrary slot in the primary PTEG to overwrite. * Since both the primary and secondary PTEGs are full, and we * have no information that the PTEs in the primary PTEG are * more important or useful than those in the secondary PTEG, * and we know there is a definite (although small) speed * advantage to putting the PTE in the primary PTEG, we always * put the PTE in the primary PTEG. */ xori r5,r5,0x2 /* clear H bit again */ lis r3,next_slot@ha tophys(r3,r3) lwz r2,next_slot@l(r3) addi r2,r2,16 andi. r2,r2,0x70#ifdef CONFIG_POWER4 /* * Since we don't have BATs on POWER4, we rely on always having * PTEs in the hash table to map the hash table and the code * that manipulates it in virtual mode, namely flush_hash_page and * flush_hash_segments. Otherwise we can get a DSI inside those * routines which leads to a deadlock on the hash_table_lock on * SMP machines. We avoid this by never overwriting the first * PTE of each PTEG if it is already valid. * -- paulus. */ bne 102f li r2,0x10102:#endif /* CONFIG_POWER4 */ stw r2,next_slot@l(r3) add r3,r4,r211: /* update counter of evicted pages */ lis r2,htab_evicts@ha tophys(r2,r2) lwz r4,htab_evicts@l(r2) addi r4,r4,1 stw r4,htab_evicts@l(r2)#ifndef CONFIG_SMP /* Store PTE in PTEG */found_empty: std r5,0(r3)found_slot: std r6,8(r3) sync#else /* CONFIG_SMP *//* * Between the tlbie above and updating the hash table entry below, * another CPU could read the hash table entry and put it in its TLB. * There are 3 cases: * 1. using an empty slot * 2. updating an earlier entry to change permissions (i.e. enable write) * 3. taking over the PTE for an unrelated address * * In each case it doesn't really matter if the other CPUs have the old * PTE in their TLB. So we don't need to bother with another tlbie here, * which is convenient as we've overwritten the register that had the * address. :-) The tlbie above is mainly to make sure that this CPU comes * and gets the new PTE from the hash table. * * We do however have to make sure that the PTE is never in an invalid * state with the V bit set. */found_empty:found_slot: li r0,1 andc r5,r5,r0 /* clear V (valid) bit in PTE */ std r5,0(r3) sync tlbsync sync std r6,8(r3) /* put in correct RPN, WIMG, PP bits */ sync ori r5,r5,1 std r5,0(r3) /* finally set V bit in PTE */#endif /* CONFIG_SMP */#else /* CONFIG_PPC64BRIDGE */ /* Construct the high word of the PPC-style PTE */ mfsrin r5,r3 /* get segment reg for segment */ rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ oris r5,r5,0x8000 /* set V (valid) bit */ rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ /* Get the address of the primary PTE group in the hash table */ .globl hash_page_patch_Ahash_page_patch_A: lis r4,Hash_base@h /* base address of hash table */ rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ xor r4,r4,r0 /* make primary hash */ /* See whether it was a PTE not found exception or a protection violation. */ andis. r0,r20,0x4000 li r2,8 /* PTEs/group */ bne 10f /* no PTE: go look for an empty slot */ tlbie r3 /* invalidate TLB entry */ /* Search the primary PTEG for a PTE whose 1st word matches r5 */ mtctr r2 addi r3,r4,-81: lwzu r0,8(r3) /* get next PTE */ cmp 0,r0,r5 bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_slot /* Search the secondary PTEG for a matching PTE */ ori r5,r5,0x40 /* set H (secondary hash) bit */ .globl hash_page_patch_Bhash_page_patch_B: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 addi r3,r3,-8 mtctr r22: lwzu r0,8(r3) cmp 0,r0,r5 bdnzf 2,2b beq+ found_slot xori r5,r5,0x40 /* clear H bit again */ /* Search the primary PTEG for an empty slot */10: mtctr r2 addi r3,r4,-8 /* search primary PTEG */1: lwzu r0,8(r3) /* get next PTE */ rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_empty /* Search the secondary PTEG for an empty slot */ ori r5,r5,0x40 /* set H (secondary hash) bit */ .globl hash_page_patch_Chash_page_patch_C: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -