head_4xx.s

来自「linux-2.4.29操作系统的源码」· S 代码 · 共 1,123 行 · 第 1/3 页

S
1,123
字号
/* *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org> *      Initial PowerPC version. *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu> *      Rewritten for PReP *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> *      Low-level exception handers, MMU support, and rewrite. *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net> *      PowerPC 8xx modifications. *    Copyright (c) 1998-1999 TiVo, Inc. *      PowerPC 403GCX modifications. *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> *      PowerPC 403GCX/405GP modifications. *    Copyright 2000 MontaVista Software Inc. *	PPC405 modifications *      PowerPC 403GCX/405GP modifications. * 	Author: MontaVista Software, Inc. *         	frank_rowand@mvista.com or source@mvista.com * 	   	debbie_chu@mvista.com * * *    Module name: head_4xx.S * *    Description: *      Kernel execution entry point code. * *    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 <asm/processor.h>#include <asm/page.h>#include <asm/mmu.h>#include <asm/pgtable.h>#include <asm/ibm4xx.h>#include <asm/cputable.h>#include <asm/ppc_asm.h>#include "ppc_defs.h"/* Preprocessor Defines */#define	STND_EXC	0#define	CRIT_EXC	1/* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet * optional, information: * *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) *   r4 - Starting address of the init RAM disk *   r5 - Ending address of the init RAM disk *   r6 - Start of kernel command line string (e.g. "mem=96m") *   r7 - End of kernel command line string * * This is all going to change RSN when we add bi_recs.......  -- Dan */	.text_GLOBAL(_stext)_GLOBAL(_start)	/* To accomodate some SMP systems that overwrite the first few	 * locations before cpu 0 starts, the bootloader starts us at 0xc.	 */	nop	nop	nop	/* Save parameters we are passed.	*/	mr	r31,r3	mr	r30,r4	mr	r29,r5	mr	r28,r6	mr	r27,r7	li	r24,0		/* CPU number */	/* We have to turn on the MMU right away so we get cache modes	 * set correctly.	 */	bl	initial_mmu/* We now have the lower 16 Meg mapped into TLB entries, and the caches * ready to work. */turn_on_mmu:	li	r0,MSR_KERNEL	mtspr	SRR1,r0	lis	r0,start_here@h	ori	r0,r0,start_here@l	mtspr	SRR0,r0	SYNC	rfi				/* enables MMU */	b	.			/* prevent prefetch past rfi */#ifdef CONFIG_405LP	/* Reserve space for ibm405lp_wakeup_info.  This contains the physical	 * address of a struct ibm405lp_wakeup_info which is used by the	 * firmware to pass control back to the kernel on cryo wakeup.  Because	 * the firmware uses this, the absolute address is fixed: don't try	 * changing it. */	. = 0xfc	.global ibm405lp_wakeup_infoibm405lp_wakeup_info:	.long	0x0#endif/* Exception vector entry code. This code runs with address translation * turned off (i.e. using physical addresses). We assume SPRG3 has the * physical address of the current task thread_struct. */#define COMMON_PROLOG							     \0:	mtspr	SPRN_SPRG0,r20;         /* We need r20, move it to SPRG0   */\	mtspr	SPRN_SPRG1,r21;         /* We need r21, move it to SPRG1   */\	mfcr	r20;                    /* We need the CR, move it to r20  */\	mfspr	r21,SPRN_SPRG2;         /* Exception stack to use          */\	cmpwi	cr0,r21,0;              /* From user mode or RTAS?         */\	bne	1f;                     /* Not RTAS, branch                */\	tophys(r21, r1);                /* Convert vka in r1 to pka in r21 */\	subi	r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame     */\1:	stw	r20,_CCR(r21);          /* Save CR on the stack            */\	stw	r22,GPR22(r21);         /* Save r22 on the stack           */\	stw	r23,GPR23(r21);         /* r23 Save on the stack           */\	mfspr	r20,SPRN_SPRG0;         /* Get r20 back out of SPRG0       */\	stw	r20,GPR20(r21);         /* Save r20 on the stack           */\	mfspr	r22,SPRN_SPRG1;         /* Get r21 back out of SPRG0       */\	stw	r22,GPR21(r21);         /* Save r21 on the stack           */\	mflr	r20;                                                         \	stw	r20,_LINK(r21);         /* Save LR on the stack            */\	mfctr	r22;                                                         \	stw	r22,_CTR(r21);          /* Save CTR on the stack           */\	mfspr	r20,XER;                                                     \	stw	r20,_XER(r21);          /* Save XER on the stack           */#define	COMMON_EPILOG							     \	stw	r0,GPR0(r21);		/* Save r0 on the stack		   */\	stw	r1,GPR1(r21);		/* Save r1 on the stack		   */\	stw	r2,GPR2(r21);		/* Save r2 on the stack		   */\	stw	r1,0(r21);						     \	tovirt(r1,r21);			/* Set-up new kernel stack pointer */\	SAVE_4GPRS(3, r21);		/* Save r3 through r6 on the stack */\	SAVE_GPR(7, r21);		/* Save r7 on the stack		   */#define	STND_EXCEPTION_PROLOG						     \	COMMON_PROLOG;							     \	mfspr	r22,SPRN_SRR0;		/* Faulting instruction address	   */\	lis	r20,MSR_WE@h;						     \	mfspr	r23,SPRN_SRR1;		/* MSR at the time of fault	   */\	andc	r23,r23,r20;		/* disable processor wait state    */\	COMMON_EPILOG;#define	CRIT_EXCEPTION_PROLOG						     \	COMMON_PROLOG;							     \	mfspr	r22,SPRN_SRR2;		/* Faulting instruction address	   */\	lis	r20,MSR_WE@h;						     \	mfspr	r23,SPRN_SRR3;		/* MSR at the time of fault	   */\	andc	r23,r23,r20;		/* disable processor wait state    */\	COMMON_EPILOG;#define	START_EXCEPTION(n, label)					     \	. = n;								     \label:#define FINISH_EXCEPTION(func)						     \	bl	transfer_to_handler;					     \	.long	func;							     \	.long	ret_from_except#define STND_EXCEPTION(n, label, func)					     \	START_EXCEPTION(n, label);					     \	STND_EXCEPTION_PROLOG;						     \	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \	li	r7,STND_EXC;						     \	li	r20,MSR_KERNEL;						     \	FINISH_EXCEPTION(func)#define	CRIT_EXCEPTION(n, label, func)					     \	START_EXCEPTION(n, label);					     \	CRIT_EXCEPTION_PROLOG;						     \	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \	li	r7,CRIT_EXC;						     \	li	r20,MSR_KERNEL;						     \	FINISH_EXCEPTION(func)/* Exception vectors.*//* 0x0100 - Critical Interrupt Exception*/	CRIT_EXCEPTION(0x0100,	CriticalInterrupt,	UnknownException)/* 0x0200 - Machine Check Exception*/	START_EXCEPTION(0x0200, MachineCheck)	CRIT_EXCEPTION_PROLOG	/*	lis	r4,0x0400	mtdcr	DCRN_POB0_BESR0,r4	*/#ifdef DCRN_POB0_BEAR	mfdcr	r4,DCRN_POB0_BEAR	mfdcr	r4,DCRN_POB0_BESR0	mfdcr	r4,DCRN_POB0_BESR1#endif#ifdef DCRN_PLB0_BEAR	mfdcr	r4,DCRN_PLB0_ACR	mfdcr	r4,DCRN_PLB0_BEAR	mfdcr	r4,DCRN_PLB0_BESR#endif	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r7,CRIT_EXC	li	r20,MSR_KERNEL	FINISH_EXCEPTION(MachineCheckException)/* 0x0300 - Data Storage Exception * This happens for just a few reasons.  U0 set (but we don't do that), * or zone protection fault (user violation, write to protected page). * If this is just an update of modified status, we do that quickly * and exit.  Otherwise, we call heavywight functions to do the work. */	START_EXCEPTION(0x0300,	DataStore)	mtspr	SPRG0, r20		/* Save some working registers */	mtspr	SPRG1, r21#ifdef CONFIG_403GCX	stw     r22, 0(r0)	stw     r23, 4(r0)	mfcr    r21	mfspr   r22, SPRN_PID	stw     r21, 8(r0)	stw     r22, 12(r0)#else	mtspr	SPRG4, r22	mtspr	SPRG5, r23	mfcr	r21	mfspr	r22, SPRN_PID	mtspr	SPRG7, r21	mtspr	SPRG6, r22#endif	/* First, check if it was a zone fault (which means a user	* tried to access a kernel or read-protected page - always	* a SEGV).  All other faults here must be stores, so no	* need to check ESR_DST as well. */	mfspr	r20, SPRN_ESR	andis.	r20, r20, ESR_DIZ@h	bne	2f	mfspr	r20, SPRN_DEAR		/* Get faulting address */	/* If we are faulting a kernel address, we have to use the	 * kernel page tables.	 */	andis.	r21, r20, 0x8000	beq	3f	lis	r21, swapper_pg_dir@h	ori	r21, r21, swapper_pg_dir@l	li	r23, 0	mtspr	SPRN_PID, r23		/* TLB will have 0 TID */	b	4f	/* Get the PGD for the current thread.	 */3:	mfspr	r21,SPRG3	lwz	r21,PGDIR(r21)4:	tophys(r21, r21)	rlwimi	r21, r20, 12, 20, 29	/* Create L1 (pgdir/pmd) address */	lwz	r21, 0(r21)		/* Get L1 entry */	rlwinm.	r22, r21, 0, 0, 19	/* Extract L2 (pte) base address */	beq	2f			/* Bail if no table */	tophys(r22, r22)	rlwimi	r22, r20, 22, 20, 29	/* Compute PTE address */	lwz	r21, 0(r22)		/* Get Linux PTE */	andi.	r23, r21, _PAGE_RW	/* Is it writeable? */	beq	2f			/* Bail if not */	/* Update 'changed'.	*/	ori	r21, r21, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE	stw	r21, 0(r22)		/* Update Linux page table */	/* Most of the Linux PTE is ready to load into the TLB LO.	 * We set ZSEL, where only the LS-bit determines user access.	 * We set execute, because we don't have the granularity to	 * properly set this at the page level (Linux problem).	 * If shared is set, we cause a zero PID->TID load.	 * Many of these bits are software only.  Bits we don't set	 * here we (properly should) assume have the appropriate value.	 */	li	r22, 0x0ce2	andc	r21, r21, r22		/* Make sure 20, 21 are zero */	ori	r21, r21, _PAGE_HWEXEC	/* make it executable */	/* find the TLB index that caused the fault.  It has to be here.	*/	tlbsx	r23, 0, r20	tlbwe	r21, r23, TLB_DATA		/* Load TLB LO */	/* Done...restore registers and get out of here.	*/#ifdef CONFIG_403GCX	lwz     r22, 12(r0)	lwz     r21, 8(r0)	mtspr   SPRN_PID, r22	mtcr    r21	lwz     r23, 4(r0)	lwz     r22, 0(r0)#else	mfspr	r22, SPRG6	mfspr	r21, SPRG7	mtspr	SPRN_PID, r22	mtcr	r21	mfspr	r23, SPRG5	mfspr	r22, SPRG4#endif	mfspr	r21, SPRG1	mfspr	r20, SPRG0	PPC405_ERR77_SYNC	rfi			/* Should sync shadow TLBs */	b	.		/* prevent prefetch past rfi */2:	/* The bailout.  Restore registers to pre-exception conditions	 * and call the heavyweights to help us out.	 */#ifdef CONFIG_403GCX	lwz     r22, 12(r0)	lwz     r21, 8(r0)	mtspr   SPRN_PID, r22	mtcr    r21	lwz     r23, 4(r0)	lwz     r22, 0(r0)#else	mfspr	r22, SPRG6	mfspr	r21, SPRG7	mtspr	SPRN_PID, r22	mtcr	r21	mfspr	r23, SPRG5	mfspr	r22, SPRG4#endif	mfspr	r21, SPRG1	mfspr	r20, SPRG0	b	DataAccess/* 0x0400 - Instruction Storage Exception * I don't know why it is called "Storage"....This is caused by a fetch * from non-execute or guarded pages. */	START_EXCEPTION(0x0400, InstructionAccess)	STND_EXCEPTION_PROLOG	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, not really needed */	stw	r5,_ESR(r21)	mr	r4,r22			/* Pass SRR0 as arg2 */	li	r5,0			/* Pass zero as arg3 */	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r7,STND_EXC	li	r20,MSR_KERNEL	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */	FINISH_EXCEPTION(do_page_fault)	/* do_page_fault(regs, SRR0, SRR1) */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?