⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 head_8xx.s

📁 linux-2.6.15.6
💻 S
📖 第 1 页 / 共 2 页
字号:
/* *  arch/ppc/kernel/except_8xx.S * *  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> *  Low-level exception handlers and MMU support *  rewritten by Paul Mackerras. *    Copyright (C) 1996 Paul Mackerras. *  MPC8xx modifications by Dan Malek *    Copyright (C) 1997 Dan Malek (dmalek@jlc.net). * *  This file contains low-level support and setup for PowerPC 8xx *  embedded processors, including trap and interrupt dispatch. * *  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/cache.h>#include <asm/pgtable.h>#include <asm/cputable.h>#include <asm/thread_info.h>#include <asm/ppc_asm.h>#include <asm/asm-offsets.h>/* Macro to make the code more readable. */#ifdef CONFIG_8xx_CPU6#define DO_8xx_CPU6(val, reg)	\	li	reg, val;	\	stw	reg, 12(r0);	\	lwz	reg, 12(r0);#else#define DO_8xx_CPU6(val, reg)#endif	.text	.globl	_stext_stext:	.text	.globl	_start_start:/* MPC8xx * This port was done on an MBX board with an 860.  Right now I only * support an ELF compressed (zImage) boot from EPPC-Bug because the * code there loads up some registers before calling us: *   r3: ptr to board info data *   r4: initrd_start or if no initrd then 0 *   r5: initrd_end - unused if r4 is 0 *   r6: Start of command line string *   r7: End of command line string * * I decided to use conditional compilation instead of checking PVR and * adding more processor specific branches around code I don't need. * Since this is an embedded processor, I also appreciate any memory * savings I can get. * * The MPC8xx does not have any BATs, but it supports large page sizes. * We first initialize the MMU to support 8M byte pages, then load one * entry into each of the instruction and data TLBs to map the first * 8M 1:1.  I also mapped an additional I/O space 1:1 so we can get to * the "internal" processor registers before MMU_init is called. * * The TLB code currently contains a major hack.  Since I use the condition * code register, I have to save and restore it.  I am out of registers, so * I just store it in memory location 0 (the TLB handlers are not reentrant). * To avoid making any decisions, I need to use the "segment" valid bit * in the first level table, but that would require many changes to the * Linux page directory/table functions that I don't want to do right now. * * I used to use SPRG2 for a temporary register in the TLB handler, but it * has since been put to other uses.  I now use a hack to save a register * and the CCR at memory location 0.....Someday I'll fix this..... *	-- Dan */	.globl	__start__start:	mr	r31,r3			/* save parameters */	mr	r30,r4	mr	r29,r5	mr	r28,r6	mr	r27,r7	/* We have to turn on the MMU right away so we get cache modes	 * set correctly.	 */	bl	initial_mmu/* We now have the lower 8 Meg mapped into TLB entries, and the caches * ready to work. */turn_on_mmu:	mfmsr	r0	ori	r0,r0,MSR_DR|MSR_IR	mtspr	SPRN_SRR1,r0	lis	r0,start_here@h	ori	r0,r0,start_here@l	mtspr	SPRN_SRR0,r0	SYNC	rfi				/* enables MMU *//* * Exception 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's thread_struct. */#define EXCEPTION_PROLOG	\	mtspr	SPRN_SPRG0,r10;	\	mtspr	SPRN_SPRG1,r11;	\	mfcr	r10;		\	EXCEPTION_PROLOG_1;	\	EXCEPTION_PROLOG_2#define EXCEPTION_PROLOG_1	\	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel */ \	andi.	r11,r11,MSR_PR;	\	tophys(r11,r1);			/* use tophys(r1) if kernel */ \	beq	1f;		\	mfspr	r11,SPRN_SPRG3;	\	lwz	r11,THREAD_INFO-THREAD(r11);	\	addi	r11,r11,THREAD_SIZE;	\	tophys(r11,r11);	\1:	subi	r11,r11,INT_FRAME_SIZE	/* alloc exc. frame */#define EXCEPTION_PROLOG_2	\	CLR_TOP32(r11);		\	stw	r10,_CCR(r11);		/* save registers */ \	stw	r12,GPR12(r11);	\	stw	r9,GPR9(r11);	\	mfspr	r10,SPRN_SPRG0;	\	stw	r10,GPR10(r11);	\	mfspr	r12,SPRN_SPRG1;	\	stw	r12,GPR11(r11);	\	mflr	r10;		\	stw	r10,_LINK(r11);	\	mfspr	r12,SPRN_SRR0;	\	mfspr	r9,SPRN_SRR1;	\	stw	r1,GPR1(r11);	\	stw	r1,0(r11);	\	tovirt(r1,r11);			/* set new kernel sp */	\	li	r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \	MTMSRD(r10);			/* (except for mach check in rtas) */ \	stw	r0,GPR0(r11);	\	SAVE_4GPRS(3, r11);	\	SAVE_2GPRS(7, r11)/* * Note: code which follows this uses cr0.eq (set if from kernel), * r11, r12 (SRR0), and r9 (SRR1). * * Note2: once we have set r1 we are in a position to take exceptions * again, and we could thus set MSR:RI at that point. *//* * Exception vectors. */#define EXCEPTION(n, label, hdlr, xfer)		\	. = n;					\label:						\	EXCEPTION_PROLOG;			\	addi	r3,r1,STACK_FRAME_OVERHEAD;	\	xfer(n, hdlr)#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret)	\	li	r10,trap;					\	stw	r10,_TRAP(r11);					\	li	r10,MSR_KERNEL;					\	copyee(r10, r9);					\	bl	tfer;						\i##n:								\	.long	hdlr;						\	.long	ret#define COPY_EE(d, s)		rlwimi d,s,0,16,16#define NOCOPY(d, s)#define EXC_XFER_STD(n, hdlr)		\	EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full,	\			  ret_from_except_full)#define EXC_XFER_LITE(n, hdlr)		\	EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \			  ret_from_except)#define EXC_XFER_EE(n, hdlr)		\	EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \			  ret_from_except_full)#define EXC_XFER_EE_LITE(n, hdlr)	\	EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \			  ret_from_except)/* System reset */	EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)/* Machine check */	. = 0x200MachineCheck:	EXCEPTION_PROLOG	mfspr r4,SPRN_DAR	stw r4,_DAR(r11)	mfspr r5,SPRN_DSISR	stw r5,_DSISR(r11)	addi r3,r1,STACK_FRAME_OVERHEAD	EXC_XFER_STD(0x200, machine_check_exception)/* Data access exception. * This is "never generated" by the MPC8xx.  We jump to it for other * translation errors. */	. = 0x300DataAccess:	EXCEPTION_PROLOG	mfspr	r10,SPRN_DSISR	stw	r10,_DSISR(r11)	mr	r5,r10	mfspr	r4,SPRN_DAR	EXC_XFER_EE_LITE(0x300, handle_page_fault)/* Instruction access exception. * This is "never generated" by the MPC8xx.  We jump to it for other * translation errors. */	. = 0x400InstructionAccess:	EXCEPTION_PROLOG	mr	r4,r12	mr	r5,r9	EXC_XFER_EE_LITE(0x400, handle_page_fault)/* External interrupt */	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)/* Alignment exception */	. = 0x600Alignment:	EXCEPTION_PROLOG	mfspr	r4,SPRN_DAR	stw	r4,_DAR(r11)	mfspr	r5,SPRN_DSISR	stw	r5,_DSISR(r11)	addi	r3,r1,STACK_FRAME_OVERHEAD	EXC_XFER_EE(0x600, alignment_exception)/* Program check exception */	EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)/* No FPU on MPC8xx.  This exception is not supposed to happen.*/	EXCEPTION(0x800, FPUnavailable, unknown_exception, EXC_XFER_STD)/* Decrementer */	EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)	EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE)	EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)/* System call */	. = 0xc00SystemCall:	EXCEPTION_PROLOG	EXC_XFER_EE_LITE(0xc00, DoSyscall)/* Single step - not used on 601 */	EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD)	EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE)	EXCEPTION(0xf00, Trap_0f, unknown_exception, EXC_XFER_EE)/* On the MPC8xx, this is a software emulation interrupt.  It occurs * for all unimplemented and illegal instructions. */	EXCEPTION(0x1000, SoftEmu, SoftwareEmulation, EXC_XFER_STD)	. = 0x1100/* * For the MPC8xx, this is a software tablewalk to load the instruction * TLB.  It is modelled after the example in the Motorola manual.  The task * switch loads the M_TWB register with the pointer to the first level table. * If we discover there is no second level table (value is zero) or if there * is an invalid pte, we load that into the TLB, which causes another fault * into the TLB Error interrupt where we can handle such problems. * We have to use the MD_xxx registers for the tablewalk because the * equivalent MI_xxx registers only perform the attribute functions. */InstructionTLBMiss:#ifdef CONFIG_8xx_CPU6	stw	r3, 8(r0)#endif	DO_8xx_CPU6(0x3f80, r3)	mtspr	SPRN_M_TW, r10	/* Save a couple of working registers */	mfcr	r10	stw	r10, 0(r0)	stw	r11, 4(r0)	mfspr	r10, SPRN_SRR0	/* Get effective address of fault */	DO_8xx_CPU6(0x3780, r3)	mtspr	SPRN_MD_EPN, r10	/* Have to use MD_EPN for walk, MI_EPN can't */	mfspr	r10, SPRN_M_TWB	/* Get level 1 table entry address */	/* If we are faulting a kernel address, we have to use the	 * kernel page tables.	 */	andi.	r11, r10, 0x0800	/* Address >= 0x80000000 */	beq	3f	lis	r11, swapper_pg_dir@h	ori	r11, r11, swapper_pg_dir@l	rlwimi	r10, r11, 0, 2, 193:	lwz	r11, 0(r10)	/* Get the level 1 entry */	rlwinm.	r10, r11,0,0,19	/* Extract page descriptor page address */	beq	2f		/* If zero, don't try to find a pte */	/* We have a pte table, so load the MI_TWC with the attributes	 * for this "segment."	 */	ori	r11,r11,1		/* Set valid bit */	DO_8xx_CPU6(0x2b80, r3)	mtspr	SPRN_MI_TWC, r11	/* Set segment attributes */	DO_8xx_CPU6(0x3b80, r3)	mtspr	SPRN_MD_TWC, r11	/* Load pte table base address */	mfspr	r11, SPRN_MD_TWC	/* ....and get the pte address */	lwz	r10, 0(r11)	/* Get the pte */	ori	r10, r10, _PAGE_ACCESSED	stw	r10, 0(r11)	/* The Linux PTE won't go exactly into the MMU TLB.	 * Software indicator bits 21, 22 and 28 must be clear.	 * Software indicator bits 24, 25, 26, and 27 must be	 * set.  All other Linux PTE bits control the behavior	 * of the MMU.	 */2:	li	r11, 0x00f0	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */	DO_8xx_CPU6(0x2d80, r3)	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */	mfspr	r10, SPRN_M_TW	/* Restore registers */	lwz	r11, 0(r0)	mtcr	r11	lwz	r11, 4(r0)#ifdef CONFIG_8xx_CPU6	lwz	r3, 8(r0)#endif	rfi	. = 0x1200DataStoreTLBMiss:#ifdef CONFIG_8xx_CPU6	stw	r3, 8(r0)#endif	DO_8xx_CPU6(0x3f80, r3)	mtspr	SPRN_M_TW, r10	/* Save a couple of working registers */	mfcr	r10	stw	r10, 0(r0)	stw	r11, 4(r0)	mfspr	r10, SPRN_M_TWB	/* Get level 1 table entry address */	/* If we are faulting a kernel address, we have to use the	 * kernel page tables.	 */	andi.	r11, r10, 0x0800	beq	3f	lis	r11, swapper_pg_dir@h	ori	r11, r11, swapper_pg_dir@l	rlwimi	r10, r11, 0, 2, 193:	lwz	r11, 0(r10)	/* Get the level 1 entry */	rlwinm.	r10, r11,0,0,19	/* Extract page descriptor page address */	beq	2f		/* If zero, don't try to find a pte */	/* We have a pte table, so load fetch the pte from the table.	 */	ori	r11, r11, 1	/* Set valid bit in physical L2 page */	DO_8xx_CPU6(0x3b80, r3)	mtspr	SPRN_MD_TWC, r11	/* Load pte table base address */	mfspr	r10, SPRN_MD_TWC	/* ....and get the pte address */	lwz	r10, 0(r10)	/* Get the pte */	/* Insert the Guarded flag into the TWC from the Linux PTE.	 * It is bit 27 of both the Linux PTE and the TWC (at least	 * I got that right :-).  It will be better when we can put	 * this into the Linux pgd/pmd and load it in the operation	 * above.	 */	rlwimi	r11, r10, 0, 27, 27	DO_8xx_CPU6(0x3b80, r3)	mtspr	SPRN_MD_TWC, r11	mfspr	r11, SPRN_MD_TWC	/* get the pte address again */	ori	r10, r10, _PAGE_ACCESSED	stw	r10, 0(r11)	/* The Linux PTE won't go exactly into the MMU TLB.	 * Software indicator bits 21, 22 and 28 must be clear.	 * Software indicator bits 24, 25, 26, and 27 must be	 * set.  All other Linux PTE bits control the behavior	 * of the MMU.	 */2:	li	r11, 0x00f0	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */	DO_8xx_CPU6(0x3d80, r3)	mtspr	SPRN_MD_RPN, r10	/* Update TLB entry */	mfspr	r10, SPRN_M_TW	/* Restore registers */	lwz	r11, 0(r0)	mtcr	r11	lwz	r11, 4(r0)#ifdef CONFIG_8xx_CPU6	lwz	r3, 8(r0)#endif	rfi/* This is an instruction TLB error on the MPC8xx.  This could be due * to many reasons, such as executing guarded memory or illegal instruction * addresses.  There is nothing to do but handle a big time error fault. */	. = 0x1300InstructionTLBError:	b	InstructionAccess

⌨️ 快捷键说明

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