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

📄 interrupt.s

📁 C++ 编写的EROS RTOS
💻 S
📖 第 1 页 / 共 5 页
字号:
	.file	"interrupt.S"/* * Copyright (C) 1998, 1999, 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * 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, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */	#include <eros/i486/asm.h>#include <eros/i486/target-asm.h>#include <arch-kerninc/PTE.hxx>#include <eros/ProcessState.h>#include <eros/Invoke.h>#define SPURIOUS_CHECK/* #define V86_SUPPORT */#define DEBUG_NESTED_IRET#if 0#define DEBUG_GP_IPC	/* requires TRAP_DEBUG */#endif#define TRAP_DEBUG	/* Following are now in the Makefile:	  #define FAST_IPC_ARG_VALIDATE  #define ASM_VALIDATE_STRINGS	*/#include "process_asm_offsets.h"#if 0#define FAST_IPC#define FAST_IPC_RETURN#define FAST_IPC_STRINGS#define FAST_IPC_REDSEG/* #define FAST_IPC_BPT */#define UNFAST_IPC_BPT#endif/* Offsets into a virgin trap frame */#define TR_OFF_SS       24#define TR_OFF_ESP      20#define TR_OFF_EFLAGS   16#define TR_OFF_CS       12#define TR_OFF_EIP       8#define TR_OFF_Error     4/* #define TR_OFF_ExceptNo  0 */	/* Offsets into stack-based IPC frame */#define IPC_invType	0#define IPC_invKey	4#define IPC_sndLen	8#define IPC_sndPtr	12#define IPC_sndKeys	16#define IPC_rcvLen	20#define IPC_rcvPtr	24#define IPC_rcvKeys	28#ifdef OPTION_OB_MOD_CHECK#define OBHDR_SZ        0x34#else#define OBHDR_SZ        0x30#endif#define OFF_THRD_CTXT   8/* * Space for the interrupt stack. * * The interrupt stack used to have an unmapped page at the bottom * to catch stack overflow.  This was never a particularly bright idea.   * If you actually managed to hit that point, you would page fault, * which would take an exception that couldn't win (because the page * was unmapped), which would in turn double fault, and the system * would just mysteriously reboot. * * Better to do an overflow test in the dispatch code until we are  * confident. *	 */			.globl EXT(InterruptStackBottom)	.globl EXT(InterruptStackLimit)	.globl EXT(InterruptStackTop)	.bss	.align 4LEXT(InterruptStackBottom)	.space 128		/* fluff for overflow check! */LEXT(InterruptStackLimit)	.space 12160		/* total stack is 8192 */LEXT(InterruptStackTop)	.data#ifdef OPTION_KERN_PROFILEGEXT(KernelProfileTable)	.long 0#endif#ifdef FAST_IPC	.align 4redflags:	.long 0redw1:	.long 0rednodekey:	.long 0keyinfo:	.long 0#endif#ifdef FAST_IPC_STATSALIGNEDVAR(nFastIpcPath,4)	.long 0ALIGNEDVAR(nFastIpcFast,4)	.long 0ALIGNEDVAR(nFastIpcRedSeg,4)	.long 0ALIGNEDVAR(nFastIpcString,4)	.long 0ALIGNEDVAR(nFastIpcSmallString,4)	.long 0ALIGNEDVAR(nFastIpcLargeString,4)	.long 0ALIGNEDVAR(nFastIpcNoString,4)	.long 0ALIGNEDVAR(nFastIpcRcvPf,4)	.long 0ALIGNEDVAR(nFastIpcEnd,4)	.long 0ALIGNEDVAR(nFastIpcPrepared,4)	.long 0/* Following is intended for use as a ``floater'' in the IPC code to   find out where things are going wrong. */ALIGNEDVAR(nFastIpcOK,4)	.long 0#endif	GEXT(DomainTracingScratchpad)	.long 0	.long 0/* * On interrupt or trap, we wish to build a stack image that captures * the per-process state.  When we are done with all of this, the stack  * will look as follows: * *  invType; *  rcvPtr; *  sndLen; *  sndPtr; *  gs     if from user mode, else unused *  fs     if from user mode, else unused *  ds     if from user mode, else unused *  es     if from user mode, else unused *  ss     if from user mode, else unused *  esp    if from user mode, else unused *  eflags *  cs *  eip *  error code (zero if none) *  trap number/interrupt number *  eax *  ecx *  edx *  ebx *  cr2  if page fault, else unused *  ebp *  esi *  edi *  cr3 *  0    <- %esp * * The zero at the bottom of the save area indicates the special * functional units, if any that need to be reloaded to resume this * thread.  On entry into the kernel, they hold the right values, so * this word is initially 0. On return, some units may need to be * reloaded, so the value may be non-zero. * * An implication of the 'unused' entries is that not all of the * SaveArea structure is necessarily valid. This is exactly true; the * kernel save area simply doesn't need to include all of the state * that the user save area does. * * ARCHITECTURAL BRAIN DEATH ALERT * * One of the more special "features" of the x86 is that it can take * exceptions on the IRET instruction.  This shouldn't happen when * returning to a kernel-mode thread, where we fully control what goes * on to the stack, but there really isn't much we can do to stop user * code from, say, attempting to load invalid segment register values. * * This isn't all that big a problem, given that we can arrange things * so as to recover properly, but one needs to be aware of it in order to * understand how the hell reload works. * * There are 5 instructions in the user process reload sequence that can  * cause a cascaded exception: * *	popl    %es *	popl    %ds *	popl    %fs *	popl    %gs * and *      iret * * The cascaded exception happens if any of the segment selectors are * inappropriate, or if fetching the instruction at CS:EIP causes a * page fault.  In that event, we will end up taking an exception back * onto the user save area before the old exception has been * completely dealt with. The exceptions that might be taken in such a * case are: * *       #GP    -- if code seg was bogus *       #SS    -- if stack seg was bogus *       #NP    -- if stack segment was not present *       #TS    -- if returning to invalid task segment *       #AC    -- if alignment checking enabled *       #PF    -- if instruction page not present * * If one of these occurs, it will push a minimum of 5 words before we * get a chance to set things right: * *      exception number *      error code *      eip *      cs *      eflags * * The trick in such a case is to patch up the stack so that it looks * like this exception was generated by the user instruction rather * than by the return path.  In the iret case, the 5 words that get * clobbered can be reconstructed from the state on the processor. * Unfortunately, the same is NOT true when a fault occurs during one * of the segment reloads. * * If a cascaded interrupt is taken, we examine the return PC to see * if it was the PC of the IRET instruction.  If so, the portion of * the save area that was smashed is: * *      SMASHED                           WITH *      error code (zero if none)         eflags *      trap number/interrupt number      kern code cs *      eax                               eip  of IRET instr *      ecx                               err code * sp-> edx                               trap no * * What we do in this case is move the err code and trap number up 3 * words (i.e. copy them into their proper positions), rewrite the * %eax, %ecx, and %edx values from the processor registers, adjust * the stack pointer to point to the bottom of the save area, and * dispatch back into OnTrapOrInterrupt */	.text	/*	 * Interrupt entry point definitions:	 */	#define DEFENTRY(vecno) \GEXT(istub##vecno) \	pushl	$0; \	pushl	$vecno; \	jmp	EXT(intr_entry)	#define DEFENTRY_EC(vecno, label) \GEXT(istub##vecno) \	pushl	$vecno; \	jmp	EXT(label)		/* Steps in the stuff below:	 *  1. Save enough to check for spurious interrupt.  Using pusha	 *     wastes about 2 cycles, but is worth it if we decide to	 *     actually TAKE the interrupt.	 *	 *  2. See if the interrupt was spurious.  If so, forget it and bail	 *	 *  3. Mark the interrupt as pending	 *	 *  4. ACK the PIC	 *	 *  5. Check if nested, and bail if appropriate	 */		/* Note that this definition only works because the kernel is	 * mapped into the user address space!!!	 */#define DEFIRQ1(pendingbit, vecno, PICbit) \GEXT(istub##vecno) \	/* Save minimal state: */; \	pushl	$0; \	pushl	$vecno; \	pusha; \	;; \	/* Disable the interrupt on the PIC: */; \	ss ; \	movb	EXT(pic1_mask),%al; \	orb	$PICbit,%al; \	outb	%al,$0x21; \	ss ; \	movb	%al,EXT(pic1_mask); \	/* ACK the PIC: */; \	movb	$0x20,%al; \	outb	%al,$0x20; \	jmp	EXT(intr_common)	#define DEFIRQ2(pendingbit, vecno, PICbit) \GEXT(istub##vecno) \	/* Save minimal state: */; \	pushl	$0; \	pushl	$vecno; \	pusha; \	;; \	/* Disable the interrupt on the PIC: */; \	ss ; \	movb	EXT(pic2_mask),%al; \	orb	$PICbit,%al; \	outb	%al,$0xa1; \	ss ; \	movb	%al,EXT(pic2_mask); \	movb	$0x20,%al; \	/* ACK the secondary PIC: */; \	outb	%al,$0xa0; \	/* ACK the primary PIC: */; \	outb	%al,$0x20; \	jmp	EXT(intr_common)	DEFENTRY(0x00)DEFENTRY(0x01)DEFENTRY(0x02)DEFENTRY(0x03)DEFENTRY(0x04)DEFENTRY(0x05)#ifdef TRAP_DEBUGDEFENTRY(0x06)#elseGEXT(istub0x06)	pushl	$0	pushl	$vecno	/* below printed at line 8, in case we die. */        ss	movl	$0x8f4e8f49,0x000b8500	/* "IN" */        ss	movl	$0x8f548f53,0x000b8504	/* "ST" */        ss	movl	$0x8f588f20,0x000b8508	/* " X" */	jmp	dump_state#endif	DEFENTRY(0x07)DEFENTRY(0x08)DEFENTRY(0x09)	/*	 * if invaltss happens in the kernel return path we'll never ses 	 * it, so don't even bother:	 */DEFENTRY_EC(0x0a, intr_entry)DEFENTRY_EC(0x0b, intr_ec)DEFENTRY_EC(0x0c, intr_ec)DEFENTRY_EC(0x0d, intr_ec)DEFENTRY_EC(0x0e, intr_pagefault)DEFENTRY(0x0f)	DEFENTRY(0x10)DEFENTRY_EC(0x11, intr_entry)	/* alignment check */DEFENTRY(0x12)		/* machine check -- not sure whether this 			   generates an EC or not */DEFENTRY(0x13)DEFENTRY(0x14)DEFENTRY(0x15)DEFENTRY(0x16)DEFENTRY(0x17)DEFENTRY(0x18)DEFENTRY(0x19)DEFENTRY(0x1a)DEFENTRY(0x1b)DEFENTRY(0x1c)DEFENTRY(0x1d)DEFENTRY(0x1e)DEFENTRY(0x1f)	/* 0x20 is clock fast path interrupt - see below */DEFIRQ1(0x2, 0x21, 0x2)DEFIRQ1(0x4, 0x22, 0x4)DEFIRQ1(0x8, 0x23, 0x8)DEFIRQ1(0x10, 0x24, 0x10)DEFIRQ1(0x20, 0x25, 0x20)DEFIRQ1(0x40, 0x26, 0x40)#ifndef SPURIOUS_CHECKDEFIRQ1(0x80, 0x27, 0x80)#endif	DEFIRQ2(0x100, 0x28, 0x1)DEFIRQ2(0x200, 0x29, 0x2)DEFIRQ2(0x400, 0x2a, 0x4)DEFIRQ2(0x800, 0x2b, 0x8)DEFIRQ2(0x1000, 0x2c, 0x10)DEFIRQ2(0x2000, 0x2d, 0x20)DEFIRQ2(0x4000, 0x2e, 0x40)#ifndef SPURIOUS_CHECKDEFIRQ2(0x8000, 0x2f, 0x80)#endif	#ifdef SPURIOUS_CHECK	/* Entry point for IRQ's 7 and 15 are a special case, because 	 * the hardware may generate spurious interrupts that we wish	 * to suppress.	 */GEXT(istub0x27)	/* Save minimal state: */;	pushl	$0	pushl	$0x27	pusha	/* Check for spurious interrupt: */	movb	$0xb,%al	outb	%al,$0x20	inb	$0x20,%al	cmpb    $0,%al		/* test sign bit -- if clear, spurious */	jge     1f		/* Disable the interrupt on the PIC: */	ss	movb	EXT(pic1_mask),%al	orb	$0x80,%al	outb	%al,$0x21	ss	movb	%al,EXT(pic1_mask)	/* ACK the PIC: */	movb	$0x20,%al	outb	%al,$0x20	jmp	EXT(intr_common)1:	/* spurious interrupt -- ack and bail */	/* ACK the PIC: */	movb	$0x20,%al	outb	%al,$0x20	jmp     EXT(.L_fast_int_exit)GEXT(istub0x2f)	/* Save minimal state: */;	pushl	$0	pushl	$0x2f	pusha	/* Check for spurious interrupt: */	movb	$0xb,%al	outb	%al,$0xa0	inb	$0xa0,%al	cmpb    $0,%al		/* test sign bit -- if clear, spurious */	jge     1f		/* Disable the interrupt on the PIC: */	ss	movb	EXT(pic2_mask),%al	orb	$0x80,%al	outb	%al,$0x21	ss	movb	%al,EXT(pic2_mask)	/* ACK both primary and secondary PIC: */	movb	$0x20,%al	outb	%al,$0x20	outb	%al,$0xa0	jmp	EXT(intr_common)1:	/* spurious interrupt -- ack and bail */	/* ACK the PIC: */	movb	$0x20,%al	outb	%al,$0x20	outb	%al,$0xa0	jmp     EXT(.L_fast_int_exit)#endif	DEFENTRY(0x30)		/* INVOCATION interrupt (0x31) is HIGH FREQUENCY, and so has been 	   moved to just above handler for benefit of cache adjacency. */	.data.LC1:	.string "Fault stack is 0x%08x\n\0"	.text	/*	 * All the interrupts that push an error code can interrupt the  	 * IRET, and we therefore may need to reshuffle the stack:	 */GEXT(intr_ec)	/* If the trap came from v86 code, or from user code, handle	   it as a user level trap. */#ifdef V86_SUPPORT	/*	 * If we interrupted a V86 task, segment registers have	 * already been saved, so no need to save them redundantly.	 */

⌨️ 快捷键说明

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