misc.s
来自「优龙2410linux2.6.8内核源代码」· S 代码 · 共 1,151 行 · 第 1/2 页
S
1,151 行
/* * arch/ppc/kernel/misc.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/offsets.h>#include <asm/cputable.h> .text/* * Returns (address we're 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) sub r3,r4,r3 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_PPC_ISERIES/* unsigned long local_save_flags(void) */_GLOBAL(local_get_flags) lbz r3,PACAPROCENABLED(r13) blr/* unsigned long local_irq_disable(void) */_GLOBAL(local_irq_disable) lbz r3,PACAPROCENABLED(r13) li r4,0 stb r4,PACAPROCENABLED(r13) blr /* Done *//* void local_irq_restore(unsigned long flags) */ _GLOBAL(local_irq_restore) lbz r5,PACAPROCENABLED(r13) /* Check if things are setup the way we want _already_. */ cmpw 0,r3,r5 beqlr /* are we enabling interrupts? */ cmpdi 0,r3,0 stb r3,PACAPROCENABLED(r13) beqlr /* Check pending interrupts */ /* A decrementer, IPI or PMC interrupt may have occurred * while we were in the hypervisor (which enables) */ ld r4,PACALPPACA+LPPACAANYINT(r13) cmpdi r4,0 beqlr /* * Handle pending interrupts in interrupt context */ li r0,0x5555 sc blr#endif /* CONFIG_PPC_ISERIES */#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_handle_irq_event) mflr r0 std r0,16(r1) stdu r1,THREAD_SIZE-112(r6) mr r1,r6 bl .handle_irq_event ld r1,0(r1) ld r0,16(r1) mtlr r0 blr#endif /* CONFIG_IRQSTACKS *//* * Flush instruction cache. */_GLOBAL(flush_instruction_cache)/* * This is called by kgdb code * and should probably go away * to be replaced by invalidating * the cache lines that are actually * modified */ /* use invalidate-all bit in HID0 * - is this consistent across all 64-bit cpus? -- paulus */ mfspr r3,HID0 ori r3,r3,HID0_ICFI mtspr HID0,r3 sync isync blr/* * 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 */_GLOBAL(__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. */ LOADADDR(r10,naca) /* Get Naca address */ ld r10,0(r10) LOADADDR(r11,systemcfg) /* Get systemcfg address */ ld r11,0(r11) lwz r7,DCACHEL1LINESIZE(r11)/* 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(r11) /* 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 /* * 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 */ LOADADDR(r10,naca) /* Get Naca address */ ld r10,0(r10) LOADADDR(r11,systemcfg) /* Get systemcfg address */ ld r11,0(r11) lwz r7,DCACHEL1LINESIZE(r11) /* 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) LOADADDR(r10,naca) /* Get Naca address */ ld r10,0(r10) LOADADDR(r11,systemcfg) /* Get systemcfg address */ ld r11,0(r11) lwz r7,DCACHEL1LINESIZE(r11) /* 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/* * 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 */ LOADADDR(r7,naca) ld r7,0(r7) LOADADDR(r8,systemcfg) /* Get systemcfg address */ ld r8,0(r8) clrrdi r3,r3,12 /* Page align */ lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ lwz r5,DCACHEL1LINESIZE(r8) /* 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(r8) /* 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 _GLOBAL(abs) cmpi 0,r3,0 bge 10f neg r3,r310: blr_GLOBAL(_get_PVR) mfspr r3,PVR blr_GLOBAL(_get_PIR) mfspr r3,PIR blr_GLOBAL(_get_HID0) mfspr r3,HID0 blr_GLOBAL(cvt_fd) lfd 0,0(r5) /* load up fpscr value */ mtfsf 0xff,0 lfs 0,0(r3) stfd 0,0(r4) mffs 0 /* save new fpscr value */ stfd 0,0(r5) blr_GLOBAL(cvt_df) lfd 0,0(r5) /* load up fpscr value */ mtfsf 0xff,0 lfd 0,0(r3) stfs 0,0(r4) mffs 0 /* save new fpscr value */ stfd 0,0(r5) 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) cmplw 0,r9,r8 beq 1f addi r3,r3,CPU_SPEC_ENTRY_SIZE b 1b1: add r0,r3,r5 std r0,0(r4) ld r4,CPU_SPEC_SETUP(r3) sub r4,r4,r5 ld r4,0(r4) sub r4,r4,r5 mtctr r4 /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ mr r4,r3 mr r3,r5 bctr/* * do_cpu_ftr_fixups - goes through the list of CPU feature fixups * and writes nop's over sections of code that don't apply for this cpu. * r3 = data offset (not changed) */_GLOBAL(do_cpu_ftr_fixups) /* Get CPU 0 features */ LOADADDR(r6,cur_cpu_spec) sub r6,r6,r3 ld r4,0(r6) sub r4,r4,r3 ld r4,CPU_SPEC_FEATURES(r4) /* Get the fixup table */ LOADADDR(r6,__start___ftr_fixup) sub r6,r6,r3 LOADADDR(r7,__stop___ftr_fixup) sub r7,r7,r3 /* Do the fixup */1: cmpld r6,r7 bgelr addi r6,r6,32 ld r8,-32(r6) /* mask */ and r8,r8,r4 ld r9,-24(r6) /* value */ cmpld r8,r9 beq 1b ld r8,-16(r6) /* section begin */ ld r9,-8(r6) /* section end */ subf. r9,r8,r9 beq 1b /* write nops over the section of code */ /* todo: if large section, add a branch at the start of it */ srwi r9,r9,2 mtctr r9 sub r8,r8,r3 lis r0,0x60000000@h /* nop */3: stw r0,0(r8) andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l beq 2f dcbst 0,r8 /* suboptimal, but simpler */ sync icbi 0,r82: addi r8,r8,4 bdnz 3b sync /* additional sync needed on g4 */ isync b 1b/* * Create a kernel thread * kernel_thread(fn, arg, flags) */_GLOBAL(kernel_thread) std r29,-24(r1)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?