iseries_head.s

来自「是关于linux2.5.1的完全源码」· S 代码 · 共 1,513 行 · 第 1/3 页

S
1,513
字号
/* *  arch/ppc/kernel/iSeries_head.S * *  Adapted from arch/ppc/kernel/head.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> *  Adapted for Power Macintosh by Paul Mackerras. *  Low-level exception handlers and MMU support *  rewritten by Paul Mackerras. *    Copyright (C) 1996 Paul Mackerras. *  Adapted for iSeries by Mike Corrigan *  Updated by Dave Boutcher *   *  This file contains the low-level support and setup for the *  iSeries LPAR platform.                                    * *  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/ppc_asm.h>#include <asm/thread_info.h>#include "ppc_defs.h"#include "iSeries_asm.h"	.text	.globl	_stext_stext:/* iSeries LPAR * * In an iSeries partition, the operating system has no direct access * to the hashed page table.  The iSeries hypervisor manages the * hashed page table, and is directed by the operating system in the * partition.  The partition, Linux in this case, always runs with * MSR.IR and MSR.DR equal to 1.  The hypervisor establishes     * addressibility for the first 64 MB of memory at 0xC0000000 by   * building a hashed page table and setting segment register 12. * * The partition memory is not physically contiguous, nor necessarily * addressable with a 32-bit address.  The hypervisor provides functions * which the kernel can use to discover the layout of memory.  The   * iSeries LPAR specific code in the kernel will build a table that maps * contiguous pseudo-real addresses starting at zero to the actual  * physical addresses owned by this partition.  In 32-bit mode we will * restrict ourselves to no more than 768 MB (or maybe 1 GB) * * When Linux interrupt handlers get control, the hypervisor has  * already saved SRR0 and SRR1 into a control block shared between * the hypervisor and Linux.  This is know as the ItLpPaca.  The values * in the actual SRR0 and SRR1 are not valid.  This requires a change in * the way the SPRG registers are used.  The definitions are: * *   Register          old definition              new definition * *   SPRG0             temp - used to save gpr     reserved for hypervisor *   SPRG1             temp - used to save gpr     addr of Paca *   SPRG2             0 or kernel stack frame     temp - used to save gpr *   SPRG3             Linux thread                Linux thread * * The Paca contains the address of the ItLpPaca.  The Paca is known only  * to Linux, while the ItLpPaca is shared between Linux and the  * hypervisor. * * The value that used to be in SPRG2 will now be saved in the Paca, * as will at least one GPR. */		.globl	__start__start:	b	start_here	. = 0x020	/* iSeries LPAR hypervisor expects a 64-bit offset of 	   the hvReleaseData structure (see HvReleaseData.h)	   at offset 0x20.  This is the base for all common	   control blocks between the hypervisor and the kernel	*/	.long	0 		.long	hvReleaseData-KERNELBASE	.long	0	.long	msChunks-KERNELBASE	.long	0	.long	pidhash-KERNELBASE	/* Pointer to start of embedded System.map */	.long	0	.globl	embedded_sysmap_startembedded_sysmap_start:	.long	0	/* Pointer to end of embedded System.map */	.long	0	.globl	embedded_sysmap_endembedded_sysmap_end:	.long	0	. = 0x060		.globl	ste_fault_countste_fault_count:	.long	0	.globl	set_context_countset_context_count:	.long	0	.globl	yield_countyield_count:	.long	0	.globl	update_times_countupdate_times_count:	.long	0	.globl	update_wall_jiffies_countupdate_wall_jiffies_count:	.long 	0	.globl	update_wall_jiffies_ticksupdate_wall_jiffies_ticks:	.long	0/* * We assume SPRG1 has the address of the Paca and SPRG3 * has the address of the task's thread_struct. * SPRG2 is used as a scratch register (as required by the * hypervisor).  SPRG0 is reserved for the hypervisor. * * The ItLpPaca has the values of SRR0 and SRR1 that the  * hypervisor saved at the point of the actual interrupt.   * * The Paca contains the value that the non-LPAR PPC Linux Kernel * keeps in SPRG2, which is either zero (if the interrupt * occurred in the kernel) or the address of the available * space on the kernel stack (if the interrupt occurred * in user code).*/#define EXCEPTION_PROLOG_1	\	mtspr	SPRG2,r20;		/* use SPRG2 as scratch reg */\	mfspr	r20,SPRG1;		/* get Paca */\	/* must do std not stw because soft disable protects	\	 * 64-bit register use (in HvCall, maybe others)	\	 */\	std	r21,PACAR21(r20);	/* Save GPR21 in Paca */\	std	r22,PACAR22(r20); 	/* Save GPR22 in Paca */\	mfcr	r22			/* Get CR */#define EXCEPTION_PROLOG_2	\	lwz	r21,PACAKSAVE(r20);	/* exception stack to use */\	cmpwi	0,r21,0;		/* user mode or kernel     */\	bne	1f;			/* 0 -> r1, else use PACAKSAVE */\	subi	r21,r1,INT_FRAME_SIZE;	/* alloc exc. frame */\1:	stw	r1,GPR1(r21);	\	mr	r1,r21;		\	stw	r22,_CCR(r1);		/* save CR in stackframe */ \	mflr	r22;		\	stw	r22,_LINK(r1);		/* Save LR in stackframe */ \	bl	save_regs;	 	/* now save everything else */ \	ld	r22,PACALPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\	ld	r23,PACALPPACA+LPPACASRR1(r20) /* Get SRR1 from ItLpPaca */#define EXCEPTION_PROLOG_EXIT	\	mtcrf	0xff,r22;	\	ld	r22,PACALPPACA+LPPACASRR0(r20);	\	ld	r21,PACALPPACA+LPPACASRR1(r20);	\	mtspr	SRR0,r22;	\	mtspr	SRR1,r21;	\	ld	r22,PACAR22(r20);	\	ld	r21,PACAR21(r20);	\	mfspr	r20,SPRG2;	\	RFI#define EXCEPTION_PROLOG	\	EXCEPTION_PROLOG_1;	\	EXCEPTION_PROLOG_2/* * 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,0;				/* soft disabled */\	bl	transfer_to_handler; 		\	.long	hdlr;				\	.long	ret_from_except/* System reset */	. = 0x100SystemReset:		mfspr	r3,SPRG3		/* Get Paca address */	mtspr	SPRG1,r3		/* Set Linux SPRG1 -> Paca */	lhz	r24,PACAPACAINDEX(r3)	/* Get processor # */	cmpi	0,r24,0			/* Are we processor 0? */	beq	start_here		/* Start up the first processor */	mfspr	r4,CTRLF	li	r5,RUNLATCH	andc	r4,r4,r5		/* Turn off the run light */	mtspr	CTRLT,r41:	HMT_LOW#ifdef CONFIG_SMP	lbz	r23,PACAPROCSTART(r3)	/* Test if this processor 					 * should start */	cmpi	0,r23,0	bne	secondary_startsecondary_smp_loop:	/* Let the Hypervisor know we are alive */	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */	lis	r3,0x8002   	rldicr 	r0,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */   	rldicl 	r3,r3,0,48		/* r3 = r3 & 0x000000000000ffff */   	or  	r3,r3,r0		/* r3 = r3 | r0			*/#else /* CONFIG_SMP */	/* Yield the processor.  This is required for non-SMP kernels	   which are running on multi-threaded machines. */	lis	r3,0x8000	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */	li	r4,0			/* "yield timed" */	li	r5,-1			/* "yield forever" */#endif /* CONFIG_SMP */	li	r0,-1			/* r0=-1 indicates a Hypervisor call */		sc				/* Invoke the hypervisor via a system call */	mfspr	r3,SPRG1 		/* Put r3 back */	b	1b			/* If SMP not configured, secondaries					 * loop forever *//* Machine check */	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)/* Data access exception. */	. = 0x300DataAccess:	EXCEPTION_PROLOG	mfspr	r4,DAR	stw	r4,_DAR(r1)	mfspr	r5,DSISR	stw	r5,_DSISR(r1)		andis.	r0,r5,0x0020		/* Is this a segment fault? */	bne	ste_fault		/* Yes - go reload segment regs */		/* This should and with 0xd7ff */	andis.	r0,r5,0xa470		/* Can we handle as little fault? */	bne	1f			/*  */		rlwinm	r3,r5,32-15,21,21	/* DSISR_STORE -> _PAGE_RW */	/* 	 * r3 contains the required access permissions	 * r4 contains the faulting address	 */	stw	r22,_NIP(r1)		/* Help with debug if dsi loop */	bl	hash_page	 	/* Try to handle as hpte fault */	lwz	r4,_DAR(r1)		/* Get original DAR */	lwz	r5,_DSISR(r1)		/* and original DSISR */1:	addi	r3,r1,STACK_FRAME_OVERHEAD	lwz	r20,_SOFTE(r1)	bl	transfer_to_handler	.long	do_page_fault	.long	ret_from_except/* Instruction access exception. */	. = 0x400InstructionAccess:	EXCEPTION_PROLOG	mr	r4,r22	mr	r5,r23	andis.	r0,r23,0x0020		/* Is this a segment fault? */	bne	ste_fault		/* Yes - go reload segment regs */		andis.	r0,r23,0x4000		/* no pte found? */	beq	1f			/* if so, try to put a PTE */	li	r3,0				bl	hash_page		/* Try to handle as hpte fault */	mr	r4,r22	mr	r5,r231:	addi	r3,r1,STACK_FRAME_OVERHEAD	lwz	r20,_SOFTE(r1)	bl	transfer_to_handler	.long	do_page_fault	.long	ret_from_except/* External interrupt */	. = 0x500;HardwareInterrupt:	EXCEPTION_PROLOG_1	lbz	r21,PACAPROCENABLED(r20)	cmpi	0,r21,0	bne	1f	EXCEPTION_PROLOG_EXIT1:	EXCEPTION_PROLOG_2do_pending_int:	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r4,0	li	r20,0			/* Soft disabled */	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(r1)	mfspr	r5,DSISR	stw	r5,_DSISR(r1)	addi	r3,r1,STACK_FRAME_OVERHEAD	lbz	r20,PACAPROCENABLED(r20)	/* preserve soft en/disabled */	bl	transfer_to_handler	.long	AlignmentException	.long	ret_from_except/* Program check exception */	. = 0x700ProgramCheck:	EXCEPTION_PROLOG	addi	r3,r1,STACK_FRAME_OVERHEAD	lbz	r20,PACAPROCENABLED(r20)	/* preserve soft en/disabled */	bl	transfer_to_handler	.long	ProgramCheckException	.long	ret_from_except/* Floating-point unavailable */	. = 0x800FPUnavailable:	EXCEPTION_PROLOG	lwz	r3,PACAKSAVE(r20)	cmpwi	0,r3,0	beq	1f	b	load_up_fpu1:	li	r20,0			/* soft disabled */	bl	transfer_to_handler	/* if from kernel, take a trap */	.long	KernelFP	.long	ret_from_except	. = 0x900Decrementer:	EXCEPTION_PROLOG_1	lbz	r21,PACAPROCENABLED(r20)	cmpi	0,r21,0	bne	1f		li	r21,1	stb	r21,PACALPPACA+LPPACADECRINT(r20)	lwz	r21,PACADEFAULTDECR(r20)	mtspr	DEC,r21	EXCEPTION_PROLOG_EXIT1:	EXCEPTION_PROLOG_2	addi	r3,r1,STACK_FRAME_OVERHEAD	li	r20,0		/* Soft disabled */	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	/* Store r3 to the kernel stack */	stw	r3,ORIG_GPR3(r1)	lbz	r20,PACAPROCENABLED(r20)	/* preserve soft en/disabled */	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)*/	STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)/*	STD_EXCEPTION(0x1400, SMI, SMIException)	STD_EXCEPTION(0x1500, Trap_15, UnknownException)	STD_EXCEPTION(0x1600, Trap_16, UnknownException)	STD_EXCEPTION(0x1700, Trap_17, TAUException)	STD_EXCEPTION(0x1800, Trap_18, UnknownException)	STD_EXCEPTION(0x1900, Trap_19, UnknownException)	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)	STD_EXCEPTION(0x2000, RunMode, RunModeException)	STD_EXCEPTION(0x2100, Trap_21, UnknownException)	STD_EXCEPTION(0x2200, Trap_22, UnknownException)	STD_EXCEPTION(0x2300, Trap_23, UnknownException)	STD_EXCEPTION(0x2400, Trap_24, UnknownException)	STD_EXCEPTION(0x2500, Trap_25, UnknownException)	STD_EXCEPTION(0x2600, Trap_26, UnknownException)	STD_EXCEPTION(0x2700, Trap_27, UnknownException)	STD_EXCEPTION(0x2800, Trap_28, UnknownException)	STD_EXCEPTION(0x2900, Trap_29, UnknownException)	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)*/	. = 0x3000	/* This code saves: CTR, XER, DAR, DSISR, SRR0, SRR1, */	/*                  r0, r2-r13, r20-r24               */	/*		    It uses R22 as a scratch register */save_regs:	ld 	r22,PACAR21(r20)	/* Get GPR21 from Paca */	stw	r22,GPR21(r1)		/* Save GPR21 in stackframe */	ld	r22,PACAR22(r20)	/* Get GPR22 from Paca */	stw	r22,GPR22(r1)		/* Save GPR22 in stackframe */	stw	r23,GPR23(r1)		/* Save GPR23 in stackframe */	stw	r24,GPR24(r1)		/* Save GPR24 in stackframe */	mfspr	r22,SPRG2		/* Get GPR20 from SPRG2 */	stw	r22,GPR20(r1)		/* Save GPR20 in stackframe */	mfctr	r22			stw	r22,_CTR(r1)		mfspr	r22,XER		stw	r22,_XER(r1)		lbz	r22,PACAPROCENABLED(r20)/* Get soft enabled/disabled */	stw	r22,_SOFTE(r1)	stw	r0,GPR0(r1) 		SAVE_8GPRS(2, r1)		SAVE_4GPRS(10, r1)		blr	ste_fault:	bl	set_kernel_segregs	mfspr	r3,SPRG1	li	r4,0	stb	r4,PACAPROCENABLED(r3)	/* Soft disable prevents going to */					/* do_pending_int on recursive fault */ 	lis	r3,ste_fault_count@ha	lwz	r4,ste_fault_count@l(r3)	addi	r4,r4,1	stw	r4,ste_fault_count@l(r3)	mfspr	r3,SPRG3		/* get thread */	addi	r3,r3,-THREAD		/* get 'current' */	lwz	r3,MM(r3)		/* get mm */	cmpi	0,r3,0			/* if no mm */	beq	1f			/* then use context 0 (kernel) */	lwz	r3,CONTEXT(r3)		/* get context */1:		/* set_context kills r0, r3, r4 and CTR */	bl	set_context		lwz	r3,_SOFTE(r1)	cmpi	0,r3,0	beq	5f			/* skip checks if restoring disabled */	CHECKANYINT(r4,r5,r6) 		/* if pending interrupts, process them */	bne-	do_pending_int5:	mfspr	r4,SPRG1	stb	r3,PACAPROCENABLED(r4)	/* Restore enabled/disabled */		b	fault_exit	/* * This code finishes saving the registers to the exception frame * and jumps to the appropriate handler for the exception, turning * on address translation. * * At this point r0-r13, r20-r24, CCR, CTR, LINK, XER, DAR and DSISR

⌨️ 快捷键说明

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