📄 misc_64.s
字号:
/* * arch/powerpc/kernel/misc64.S * * This file contains miscellaneous low-level functions. * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras. * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * * 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 <linux/config.h>#include <linux/sys.h>#include <asm/unistd.h>#include <asm/errno.h>#include <asm/processor.h>#include <asm/page.h>#include <asm/cache.h>#include <asm/ppc_asm.h>#include <asm/asm-offsets.h>#include <asm/cputable.h>#include <asm/thread_info.h> .text/* * Returns (address we are running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. */_GLOBAL(reloc_offset) mflr r0 bl 1f1: mflr r3 LOADADDR(r4,1b) subf r3,r4,r3 mtlr r0 blr/* * add_reloc_offset(x) returns x + reloc_offset(). */_GLOBAL(add_reloc_offset) mflr r0 bl 1f1: mflr r5 LOADADDR(r4,1b) subf r5,r4,r5 add r3,r3,r5 mtlr r0 blr_GLOBAL(get_msr) mfmsr r3 blr_GLOBAL(get_dar) mfdar r3 blr_GLOBAL(get_srr0) mfsrr0 r3 blr_GLOBAL(get_srr1) mfsrr1 r3 blr _GLOBAL(get_sp) mr r3,r1 blr#ifdef CONFIG_IRQSTACKS_GLOBAL(call_do_softirq) mflr r0 std r0,16(r1) stdu r1,THREAD_SIZE-112(r3) mr r1,r3 bl .__do_softirq ld r1,0(r1) ld r0,16(r1) mtlr r0 blr_GLOBAL(call___do_IRQ) mflr r0 std r0,16(r1) stdu r1,THREAD_SIZE-112(r5) mr r1,r5 bl .__do_IRQ ld r1,0(r1) ld r0,16(r1) mtlr r0 blr#endif /* CONFIG_IRQSTACKS */ /* * To be called by C code which needs to do some operations with MMU * disabled. Note that interrupts have to be disabled by the caller * prior to calling us. The code called _MUST_ be in the RMO of course * and part of the linear mapping as we don't attempt to translate the * stack pointer at all. The function is called with the stack switched * to this CPU emergency stack * * prototype is void *call_with_mmu_off(void *func, void *data); * * the called function is expected to be of the form * * void *called(void *data); */_GLOBAL(call_with_mmu_off) mflr r0 /* get link, save it on stackframe */ std r0,16(r1) mr r1,r5 /* save old stack ptr */ ld r1,PACAEMERGSP(r13) /* get emerg. stack */ subi r1,r1,STACK_FRAME_OVERHEAD std r0,16(r1) /* save link on emerg. stack */ std r5,0(r1) /* save old stack ptr in backchain */ ld r3,0(r3) /* get to real function ptr (assume same TOC) */ bl 2f /* we need LR to return, continue at label 2 */ ld r0,16(r1) /* we return here from the call, get LR and */ ld r1,0(r1) /* .. old stack ptr */ mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ mfmsr r4 ori r4,r4,MSR_IR|MSR_DR mtspr SPRN_SRR1,r4 rfid2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ mr r3,r4 /* get parameter */ mfmsr r0 ori r0,r0,MSR_IR|MSR_DR xori r0,r0,MSR_IR|MSR_DR mtspr SPRN_SRR1,r0 rfid .section ".toc","aw"PPC64_CACHES: .tc ppc64_caches[TC],ppc64_caches .section ".text"/* * Write any modified data cache blocks out to memory * and invalidate the corresponding instruction cache blocks. * * flush_icache_range(unsigned long start, unsigned long stop) * * flush all bytes from start through stop-1 inclusive */_KPROBE(__flush_icache_range)/* * Flush the data cache to memory * * Different systems have different cache line sizes * and in some cases i-cache and d-cache line sizes differ from * each other. */ ld r10,PPC64_CACHES@toc(r2) lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 /* ensure we get enough */ lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mtctr r81: dcbst 0,r6 add r6,r6,r7 bdnz 1b sync/* Now invalidate the instruction cache */ lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mtctr r82: icbi 0,r6 add r6,r6,r7 bdnz 2b isync blr .previous .text/* * Like above, but only do the D-cache. * * flush_dcache_range(unsigned long start, unsigned long stop) * * flush all bytes from start to stop-1 inclusive */_GLOBAL(flush_dcache_range)/* * Flush the data cache to memory * * Different systems have different cache line sizes */ ld r10,PPC64_CACHES@toc(r2) lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 /* ensure we get enough */ lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mtctr r80: dcbst 0,r6 add r6,r6,r7 bdnz 0b sync blr/* * Like above, but works on non-mapped physical addresses. * Use only for non-LPAR setups ! It also assumes real mode * is cacheable. Used for flushing out the DART before using * it as uncacheable memory * * flush_dcache_phys_range(unsigned long start, unsigned long stop) * * flush all bytes from start to stop-1 inclusive */_GLOBAL(flush_dcache_phys_range) ld r10,PPC64_CACHES@toc(r2) lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 /* ensure we get enough */ lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mfmsr r5 /* Disable MMU Data Relocation */ ori r0,r5,MSR_DR xori r0,r0,MSR_DR sync mtmsr r0 sync isync mtctr r80: dcbst 0,r6 add r6,r6,r7 bdnz 0b sync isync mtmsr r5 /* Re-enable MMU Data Relocation */ sync isync blr_GLOBAL(flush_inval_dcache_range) ld r10,PPC64_CACHES@toc(r2) lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 /* ensure we get enough */ lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ sync isync mtctr r80: dcbf 0,r6 add r6,r6,r7 bdnz 0b sync isync blr/* * Flush a particular page from the data cache to RAM. * Note: this is necessary because the instruction cache does *not* * snoop from the data cache. * * void __flush_dcache_icache(void *page) */_GLOBAL(__flush_dcache_icache)/* * Flush the data cache to memory * * Different systems have different cache line sizes *//* Flush the dcache */ ld r7,PPC64_CACHES@toc(r2) clrrdi r3,r3,PAGE_SHIFT /* Page align */ lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ mr r6,r3 mtctr r40: dcbst 0,r6 add r6,r6,r5 bdnz 0b sync/* Now invalidate the icache */ lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ mtctr r41: icbi 0,r3 add r3,r3,r5 bdnz 1b isync blr /* * I/O string operations * * insb(port, buf, len) * outsb(port, buf, len) * insw(port, buf, len) * outsw(port, buf, len) * insl(port, buf, len) * outsl(port, buf, len) * insw_ns(port, buf, len) * outsw_ns(port, buf, len) * insl_ns(port, buf, len) * outsl_ns(port, buf, len) * * The *_ns versions don't do byte-swapping. */_GLOBAL(_insb) cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 blelr-00: lbz r5,0(r3) eieio stbu r5,1(r4) bdnz 00b twi 0,r5,0 isync blr_GLOBAL(_outsb) cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 blelr-00: lbzu r5,1(r4) stb r5,0(r3) bdnz 00b sync blr _GLOBAL(_insw) cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr-00: lhbrx r5,0,r3 eieio sthu r5,2(r4) bdnz 00b twi 0,r5,0 isync blr_GLOBAL(_outsw) cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr-00: lhzu r5,2(r4) sthbrx r5,0,r3 bdnz 00b sync blr _GLOBAL(_insl) cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr-00: lwbrx r5,0,r3 eieio stwu r5,4(r4) bdnz 00b twi 0,r5,0 isync blr_GLOBAL(_outsl) cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr-00: lwzu r5,4(r4) stwbrx r5,0,r3 bdnz 00b sync blr /* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */_GLOBAL(_insw_ns) cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr-00: lhz r5,0(r3) eieio sthu r5,2(r4) bdnz 00b twi 0,r5,0 isync blr/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */_GLOBAL(_outsw_ns) cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 blelr-00: lhzu r5,2(r4) sth r5,0(r3) bdnz 00b sync blr _GLOBAL(_insl_ns) cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr-00: lwz r5,0(r3) eieio stwu r5,4(r4) bdnz 00b twi 0,r5,0 isync blr_GLOBAL(_outsl_ns) cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 blelr-00: lwzu r5,4(r4) stw r5,0(r3) bdnz 00b sync blr /* * identify_cpu and calls setup_cpu * In: r3 = base of the cpu_specs array * r4 = address of cur_cpu_spec * r5 = relocation offset */_GLOBAL(identify_cpu) mfpvr r71: lwz r8,CPU_SPEC_PVR_MASK(r3) and r8,r8,r7 lwz r9,CPU_SPEC_PVR_VALUE(r3)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -