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

📄 head_8xx.s

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 S
📖 第 1 页 / 共 2 页
字号:
/* *  arch/ppc/kernel/except_8xx.S * *  $Id: head_8xx.S,v 1.4 1999/09/18 18:43:19 dmalek Exp $ * *  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 "ppc_asm.h"#include <asm/processor.h>#include <asm/page.h>#include <linux/config.h>#include <asm/mmu.h>#include <asm/cache.h>#include <asm/pgtable.h>	/* XXX need definitions here for 16 byte cachelines on some/all 8xx   -- paulus */CACHELINE_BYTES = 32LG_CACHELINE_BYTES = 5CACHELINE_MASK = 0x1fCACHELINE_WORDS = 8	.text	.globl	_stext_stext:/* * _start is defined this way because the XCOFF loader in the OpenFirmware * on the powermac expects the entry point to be a procedure descriptor. */	.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	li	r24,0			/* cpu # */	tlbia			/* Invalidate all TLB entries */	li	r8, 0	mtspr	MI_CTR, r8	/* Set instruction control to zero */	lis	r8, MD_RESETVAL@h#ifndef CONFIG_8xx_COPYBACK	oris	r8, r8, MD_WTDEF@h#endif	mtspr	MD_CTR, r8	/* Set data TLB control */	/* Now map the lower 8 Meg into the TLBs.  For this quick hack,	 * we can load the instruction and data TLB registers with the	 * same values.	 */	lis	r8, KERNELBASE@h	/* Create vaddr for TLB */	ori	r8, r8, MI_EVALID	/* Mark it valid */	mtspr	MI_EPN, r8	mtspr	MD_EPN, r8	li	r8, MI_PS8MEG		/* Set 8M byte page */	ori	r8, r8, MI_SVALID	/* Make it valid */	mtspr	MI_TWC, r8	mtspr	MD_TWC, r8	li	r8, MI_BOOTINIT		/* Create RPN for address 0 */	mtspr	MI_RPN, r8		/* Store TLB entry */	mtspr	MD_RPN, r8	lis	r8, MI_Kp@h		/* Set the protection mode */	mtspr	MI_AP, r8	mtspr	MD_AP, r8	/* Map another 8 MByte at the IMMR to get the processor	 * internal registers (among other things).	 */	mfspr	r9, 638			/* Get current IMMR */	andis.	r9, r9, 0xff80		/* Get 8Mbyte boundary */	mr	r8, r9			/* Create vaddr for TLB */	ori	r8, r8, MD_EVALID	/* Mark it valid */	mtspr	MD_EPN, r8	li	r8, MD_PS8MEG		/* Set 8M byte page */	ori	r8, r8, MD_SVALID	/* Make it valid */	mtspr	MD_TWC, r8	mr	r8, r9			/* Create paddr for TLB */	ori	r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */	mtspr	MD_RPN, r8	/* Since the cache is enabled according to the information we	 * just loaded into the TLB, invalidate and enable the caches here.	 * We should probably check/set other modes....later.	 */	lis	r8, IDC_INVALL@h	mtspr	IC_CST, r8	mtspr	DC_CST, r8	lis	r8, IDC_ENABLE@h	mtspr	IC_CST, r8#ifdef CONFIG_8xx_COPYBACK	mtspr	DC_CST, r8#else	/* For a debug option, I left this here to easily enable	 * the write through cache mode	 */	lis	r8, DC_SFWT@h	mtspr	DC_CST, r8	lis	r8, IDC_ENABLE@h	mtspr	DC_CST, r8#endif/* 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	SRR1,r0	lis	r0,start_here@h	ori	r0,r0,start_here@l	mtspr	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	SPRG0,r20;	\	mtspr	SPRG1,r21;	\	mfcr	r20;		\	mfspr	r21,SPRG2;		/* exception stack to use from */ \	cmpwi	0,r21,0;		/* user mode or RTAS */ \	bne	1f;		\	tophys(r21,r1);			/* use tophys(kernel sp) otherwise */ \	subi	r21,r21,INT_FRAME_SIZE;	/* alloc exc. frame */\1:	stw	r20,_CCR(r21);		/* save registers */ \	stw	r22,GPR22(r21);	\	stw	r23,GPR23(r21);	\	mfspr	r20,SPRG0;	\	stw	r20,GPR20(r21);	\	mfspr	r22,SPRG1;	\	stw	r22,GPR21(r21);	\	mflr	r20;		\	stw	r20,_LINK(r21);	\	mfctr	r22;		\	stw	r22,_CTR(r21);	\	mfspr	r20,XER;	\	stw	r20,_XER(r21);	\	mfspr	r22,SRR0;	\	mfspr	r23,SRR1;	\	stw	r0,GPR0(r21);	\	stw	r1,GPR1(r21);	\	stw	r2,GPR2(r21);	\	stw	r1,0(r21);	\	tovirt(r1,r21);			/* set new kernel sp */	\	SAVE_4GPRS(3, r21);	\	SAVE_GPR(7, r21);/* * Note: code which follows this uses cr0.eq (set if from kernel), * r21, r22 (SRR0), and r23 (SRR1). *//* * Exception vectors. */#define STD_EXCEPTION(n, label, hdlr)		\	. = n;					\label:						\	EXCEPTION_PROLOG;			\	addi	r3,r1,STACK_FRAME_OVERHEAD;	\	li	r20,MSR_KERNEL;			\	bl	transfer_to_handler; 		\	.long	hdlr;				\	.long	ret_from_except/* System reset */#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */	STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)#else	STD_EXCEPTION(0x100, Reset, UnknownException)#endif	/* Machine check */	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)/* Data access exception. * This is "never generated" by the MPC8xx.  We jump to it for other * translation errors. */	. = 0x300DataAccess:	EXCEPTION_PROLOG	mfspr	r20,DSISR	stw	r20,_DSISR(r21)	mr	r5,r20	mfspr	r4,DAR	stw	r4,_DAR(r21)	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r20,MSR_KERNEL	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */	bl	transfer_to_handler	.long	do_page_fault	.long	ret_from_except/* Instruction access exception. * This is "never generated" by the MPC8xx.  We jump to it for other * translation errors. */	. = 0x400InstructionAccess:	EXCEPTION_PROLOG	addi	r3,r1,STACK_FRAME_OVERHEAD	mr	r4,r22	mr	r5,r23	li	r20,MSR_KERNEL	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */	bl	transfer_to_handler	.long	do_page_fault	.long	ret_from_except/* External interrupt */	. = 0x500;HardwareInterrupt:	EXCEPTION_PROLOG;	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r20,MSR_KERNEL	li	r4,0	bl	transfer_to_handler	.globl do_IRQ_interceptdo_IRQ_intercept:	.long	do_IRQ;	.long	ret_from_intercept	/* Alignment exception */	. = 0x600Alignment:	EXCEPTION_PROLOG	mfspr	r4,DAR	stw	r4,_DAR(r21)	mfspr	r5,DSISR	stw	r5,_DSISR(r21)	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r20,MSR_KERNEL	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */	bl	transfer_to_handler	.long	AlignmentException	.long	ret_from_except/* Program check exception */	. = 0x700ProgramCheck:	EXCEPTION_PROLOG	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r20,MSR_KERNEL	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */	bl	transfer_to_handler	.long	ProgramCheckException	.long	ret_from_except/* No FPU on MPC8xx.  This exception is not supposed to happen.*/	STD_EXCEPTION(0x800, FPUnavailable, UnknownException)	. = 0x900Decrementer:	EXCEPTION_PROLOG	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r20,MSR_KERNEL	bl	transfer_to_handler	.globl timer_interrupt_intercepttimer_interrupt_intercept:	.long	timer_interrupt	.long	ret_from_intercept	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)/* System call */	. = 0xc00SystemCall:	EXCEPTION_PROLOG	stw	r3,ORIG_GPR3(r21)	li	r20,MSR_KERNEL	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */	bl	transfer_to_handler	.long	DoSyscall	.long	ret_from_except/* Single step - not used on 601 */	STD_EXCEPTION(0xd00, SingleStep, SingleStepException)	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)/* On the MPC8xx, this is a software emulation interrupt.  It occurs * for all unimplemented and illegal instructions. */	STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation)	. = 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 (the value is zero), the * plan was to load that into the TLB, which causes another fault into the * TLB Error interrupt where we can handle such problems.  However, that did * not work, so if we discover there is no second level table, we restore * registers and branch to the error exception.  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)	li	r3, 0x3f80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	M_TW, r20	/* Save a couple of working registers */	mfcr	r20	stw	r20, 0(r0)	stw	r21, 4(r0)	mfspr	r20, SRR0	/* Get effective address of fault */#ifdef CONFIG_8xx_CPU6	li	r3, 0x3780	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	MD_EPN, r20	/* Have to use MD_EPN for walk, MI_EPN can't */	mfspr	r20, M_TWB	/* Get level 1 table entry address */	/* If we are faulting a kernel address, we have to use the	 * kernel page tables.	 */	andi.	r21, r20, 0x0800	/* Address >= 0x80000000 */	beq	3f	lis	r21, swapper_pg_dir@h	ori	r21, r21, swapper_pg_dir@l	rlwimi	r20, r21, 0, 2, 193:	lwz	r21, 0(r20)	/* Get the level 1 entry */	rlwinm.	r20, r21,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 page, which has only bit 31 set.	 */	tophys(r21,r21)	ori	r21,r21,1		/* Set valid bit */#ifdef CONFIG_8xx_CPU6	li	r3, 0x2b80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	MI_TWC, r21	/* Set page attributes */#ifdef CONFIG_8xx_CPU6	li	r3, 0x3b80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	MD_TWC, r21	/* Load pte table base address */	mfspr	r21, MD_TWC	/* ....and get the pte address */	lwz	r20, 0(r21)	/* Get the pte */#if 0	ori	r20, r20, _PAGE_ACCESSED	stw	r20, 0(r21)#endif	/* Set four subpage valid bits (24, 25, 26, and 27).	 * Clear bit 28 (which should be in the PTE, but we do this anyway).	 */	li	r21, 0x00f0	rlwimi	r20, r21, 0, 24, 28#ifdef CONFIG_8xx_CPU6	li	r3, 0x2d80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	MI_RPN, r20	/* Update TLB entry */	mfspr	r20, M_TW	/* Restore registers */	lwz	r21, 0(r0)	mtcr	r21	lwz	r21, 4(r0)#ifdef CONFIG_8xx_CPU6	lwz	r3, 8(r0)#endif	rfi2:	mfspr	r20, M_TW	/* Restore registers */	lwz	r21, 0(r0)	mtcr	r21	lwz	r21, 4(r0)#ifdef CONFIG_8xx_CPU6	lwz	r3, 8(r0)#endif	b	InstructionAccess	. = 0x1200DataStoreTLBMiss:#ifdef CONFIG_8xx_CPU6	stw	r3, 8(r0)	li	r3, 0x3f80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	M_TW, r20	/* Save a couple of working registers */	mfcr	r20	stw	r20, 0(r0)	stw	r21, 4(r0)	mfspr	r20, M_TWB	/* Get level 1 table entry address */	/* If we are faulting a kernel address, we have to use the	 * kernel page tables.	 */	andi.	r21, r20, 0x0800	beq	3f	lis	r21, swapper_pg_dir@h	ori	r21, r21, swapper_pg_dir@l	rlwimi r20, r21, 0, 2, 193:	lwz	r21, 0(r20)	/* Get the level 1 entry */	rlwinm.	r20, r21,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.	 */	tophys(r21, r21)	ori	r21, r21, 1	/* Set valid bit in physical L2 page */#ifdef CONFIG_8xx_CPU6	li	r3, 0x3b80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	MD_TWC, r21	/* Load pte table base address */	mfspr	r20, MD_TWC	/* ....and get the pte address */	lwz	r20, 0(r20)	/* 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	r21, r20, 0, 27, 27#ifdef CONFIG_8xx_CPU6	li	r3, 0x3b80	stw	r3, 12(r0)	lwz	r3, 12(r0)#endif	mtspr	MD_TWC, r21	/* Set four subpage valid bits (24, 25, 26, and 27).	 * Clear bit 28 (which should be in the PTE, but we do this anyway).	 */#if 0	ori	r20, r20, 0x00f0#else	li	r21, 0x00f0	rlwimi	r20, r21, 0, 24, 28#endif#ifdef CONFIG_8xx_CPU6	li	r3, 0x3d80	stw	r3, 12(r0)

⌨️ 快捷键说明

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