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 + -
显示快捷键?