?? i8259intrpep.c
字號(hào):
/* i8259IntrPep.c - Intel 8259A PIC (Programmable Interrupt Controller) driver *//* Copyright 1984-2002 Wind River Systems, Inc. *//* Copyright 2002 Kontron Modular Computers GmbH */#include "copyright_wrs.h"/*modification history--------------------01r,12nov02,gko IRQ15 bug has also been detected by support (PDR 02104174), adapted to pep folder structure, version identifier01q,11nov02,hdn fixed the IRQ15 spurious interrupt handling (spr 74209)01p,16apr02,hdn added support for the Special Fully Nested Mode, IRQ0 Early EOI Mode, IRQ0 Special Mask Mode, AEOI Mode (spr 76411)01o,29mar02,hdn added forgotten back slash to the optimized code01n,21mar02,hdn fixed doc build by removing comments in the optimized code01m,25feb02,hdn updated i8259Init() for HTT (spr 73738) added optimized version of EOI routines01l,11sep01,hdn updated comment regarding the spr-28547 fix.01k,27aug99,hdn fixed a bug for stray interrupt in i8259IntBoi(SPR 28547).01j,11oct98,ms fixed compiler warning via typecast01i,04jun98,hdn changed a method to exit i8259IntBoi().01h,25may98,hdn changed function name starting from "i8259". added i8259IntEoiMaster(), i8259IntEoiSlave(), i8259IntBoi(). removed sysIntEOI().01g,17mar97,hdn added sysIntLock(), sysIntUnlock() for the system mode.01f,25jun96,hdn added sysIntLevel() for windview.01e,23may96,wlf doc: cleanup.01d,14jun95,hdn renamed sysEndOfInt to sysIntEOI. moved global function prototypes to sysLib.h.01c,08aug94,hdn stopped toggling IRQ9 in enabling and disabling.01b,22apr94,hdn made IRQ9 off in the initialization. moved sysVectorIRQ0 to sysLib.c.01a,05sep93,hdn written.*//*DESCRIPTIONThis module is a driver for the Intel 8259A PIC (Programmable InterruptController). The Intel 8259A handles up to 8 vectored priority interruptsfor the CPU. It is cascadable for up to 64 vectored priority interrupts,though this driver assumes two cascaded 8259A. It is initialized for"Fully Nested Mode", "Non-Specific EOI" mode.Fully Nested Mode.In this mode, interrupt requests are ordered in priorityfrom 0 through 7 (0 is the highest priority). When an interrupt isacknowledged, the highest priority request is determined and its vector isplaced on the bus. Additionally, a bit of the Interrupt Service (IS)register is set. This bit remains set until the microprocessor issues anEOI command immediately before returning from the service routine. Whilethe IS bit is set, all further interrupts of the same or lower priorityare inhibited, while higher level interrupts are allowed. Thei8259IntEoiSlaveNfnm() routine is used to issue the EOI command. The PICsin a PC typically operate in this mode (normal nested mode). In this mode,while the slave PIC is being serviced by the master PIC, the slave PIC blocksall higher priority interrupt requests. Alternatively, to allow interrupts ofa higher priority, enable the Special Fully Nested Mode.Special Fully Nested Mode: I8259_SPECIAL_FULLY_NESTED_MODE.This mode is similar to the Fully Nested Mode with the following exceptions:1) When an interrupt request from a slave PIC is in service, the slave isnot locked out from the master's priority logic and further interruptrequests from higher priority IRs within the slave will be recognized bythe master and will initiate interrupts to the processor. 2) When exitingthe interrupt service routine, the software must check whether or not theinterrupt serviced was the only interrupt request from the slave. If itwas the only interrupt request, a non-specific EOI is sent to the master.If not, no EOI is sent. This is implemented by the i8259EoiSlaveSfnm()routine.Non-Specific EOI: When the 8259A is operated in the Fully Nested Mode, itcan determine which IS bit to reset on EOI. When a non-specific EOIcommand is issued, the 8259A will automatically reset the highest IS bit ofthose that are set, since in the fully nested mode the highest IS level isthe last level acknowledged and serviced.Spurious/Phantom Interrupt: The IR inputs must remain high until after thefalling edge of the first INTA. If the IR input goes low before this time,a DEFAULT(Spurious/Phantom) IR7 will occur when the CPU acknowledges theinterrupt. The interrupt handler should simply return without sendingan EOI command.The PIC(8259A) IRQ0 is hard wired to the PIT(8253) channel 0 in a PCmotherboard. IRQ0 is the highest priority in the 8259A interruptcontroller. Thus, the system clock interrupt handler blocks all lowerlevel interrupts. This may cause a delay of the lower level interrupts insome situations even though the system clock interrupt handler finishes itsjob without any delay. This is quite natural from the hardware point ofview, but may not be ideal from the application software standpoint. Thefollowing modes are supplied to mitigate this situation by providingcorresponding configuration macros in the BSP. The three modes are mutuallyexclusive.Early EOI Issue in IRQ0 ISR.In this mode, the EOI command is issued before the IRQ0 system clock interruptservice routine starts the kernel work. This lowers the IRQ0 ISR blockinglevel to the next lower level. If no IRQs are in service, the next lowerlevel is the lowest level. If IRQn is in service, the next lower levelcorresponds to the next lower priority. As a result, the kernel work in thesystem clock interrupt service routine can be interrupted by an interruptwith a higher priority than the blocking level. The i8259IntBoiEem() routine is called before the interrupt service routine, and no EOI is sent after the interrupt service routine.Special Mask Mode in IRQ0 ISR.In this mode, the Special Mask Mode is used in the IRQ0 system clockservice routine. This lowers the blocking level to the specified level(currently hard coded to the lowest level). The i8259IntBoiSmm() routineis called before the interrupt service routine, and the i8259IntEoiSmm()routine is called after the interrupt service routine.Automatic EOI Mode: I8259_AUTO_EOI.This mode provides no nested multi-level interrupt structure in PIC1. TheEOI command is automatically sent to the master PIC at the end of theinterrupt acknowledge cycle. Thus, no software intervention is needed. Thei8259IntBoi() routine is called before the IRQ7 and IRQ15 interrupt serviceroutines. Either the i8259IntEoiSlaveNfnm() routine or thei8259IntEoiSlaveSfnm() routine is called after the slave PIC's interruptservice routine.SEE ALSO: pc386/target.nr*/#include "drv/intrCtl/i8259Pep.h"#include "versionPep.h"/* version identifier */PEP_VERSION(i8259IntrPep_c,01r)/* externs */IMPORT void intBoiExit ();IMPORT UINT32 sysStrayIntCount;IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP *//* defines */#define I8259_EOI_OPTIMIZED /* use the optimized version *//* globals *//* local */#ifndef SYMMETRIC_IO_MODELOCAL INT8 i8259IntMask1; /* interrupt mask for PIC1 */LOCAL INT8 i8259IntMask2; /* interrupt mask for PIC2 */LOCAL INT8 i8259Mask = 0; /* interrupt mask for PIC1 */#endif /* SYMMETRIC_IO_MODE *//* forward static functions *//********************************************************************************* i8259Init - initialize the PIC** This routine initializes the PIC.**/VOID i8259Init (void) { UINT8 icw4 = 0x01; /* return if it is not the Boot Processor (BP) */ if (sysBp == FALSE) return; /* initialize the PIC (Programmable Interrupt Controller) */ sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */ sysOutByte (PIC_port2 (PIC1_BASE_ADR),INT_NUM_IRQ0); /* ICW2 */ sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */#ifdef I8259_SPECIAL_FULLY_NESTED_MODE icw4 |= 0x10; /* SFNM */#endif /* I8259_SPECIAL_FULLY_NESTED_MODE */#ifdef I8259_AUTO_EOI icw4 |= 0x02; /* AEOI */#endif /* I8259_AUTO_EOI */ sysOutByte (PIC_port2 (PIC1_BASE_ADR),icw4); /* ICW4 */ sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */ sysOutByte (PIC_port2 (PIC2_BASE_ADR),INT_NUM_IRQ0+8); /* ICW2 */ sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */ sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */ /* disable interrupts */ sysOutByte (PIC_IMASK (PIC1_BASE_ADR),0xfb); sysOutByte (PIC_IMASK (PIC2_BASE_ADR),0xff); }#ifndef SYMMETRIC_IO_MODE/********************************************************************************* i8259IntBoiEem - issue EOI before the IRQ0 interrupt handler** This routine is called before the IRQ0 interrupt handler that is PIT(8253)* channel 0 system clock interrupt handler in the Early EOI Mode.**/VOID i8259IntBoiEem ( int irqNo /* IRQ number of the interrupt */ ) { INT32 oldLevel = intLock (); /* LOCK INTERRUPT */ sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */ intUnlock (oldLevel); /* UNLOCK INTERRUPT */ }/********************************************************************************* i8259IntBoiSmm - enable Special Mask Mode before the IRQ0 interrupt handler** This routine is called before the IRQ0 interrupt handler that is PIT(8253)* channel 0 system clock interrupt handler, in the Special Mask Mode.**/VOID i8259IntBoiSmm ( int irqNo /* IRQ number of the interrupt */ ) { INT32 oldLevel = intLock (); /* LOCK INTERRUPT */ sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x68); /* enable SMM PIC1 */ i8259Mask = sysInByte (PIC_IMASK (PIC1_BASE_ADR)); /* save int mask */ sysOutByte (PIC_IMASK (PIC1_BASE_ADR), 0x01); /* unlock except IRQ0 */ intUnlock (oldLevel); /* UNLOCK INTERRUPT */ }/********************************************************************************* i8259IntBoi - detect whether it is spurious interrupt or not** This routine is called before the user's interrupt handler to detect the* spurious interrupt.**/VOID i8259IntBoi ( INT32 irqNo /* IRQ number of the interrupt */ ) { INT32 oldLevel; INT8 inserviceReg; INT8 inserviceRegTmp; /* we are interested in IRQ7 and IRQ15 */ if ((irqNo != 7) && (irqNo != 15)) return; /* if ISR bit is not set, we change the return address */ oldLevel = intLock (); /* LOCK INTERRUPT */ if (irqNo == 7) { sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b); inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR)); } else { sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b); inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR)); /* check bit7 for spurious interrupt from the slave PIC IRQ15 */ if ((inserviceReg & 0x80) == 0) { /* make sure no IRQs in the slave PIC are in service */ if (inserviceReg == 0) { /* check the master PIC's in-service register */ sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b); inserviceRegTmp = sysInByte (PIC_port1 (PIC1_BASE_ADR)); /* send non-specific EOI to the master PIC IRQ2 */ if (inserviceRegTmp & 0x04) sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); } } } intUnlock (oldLevel); /* UNLOCK INTERRUPT */ /* * another implementation idea... * * *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit; * This changes the return addr on the stack. This is architecture * specific and tricky. Thus making following change may be good idea. * * - let this routine return OK or ERROR * - let interrupt stub code check the ret value and jump to intExit. * * New code would be like this: * : * if ((irqNo != 7) && (irqNo != 15)) * return (OK); * : * if ((inserviceReg & 0x80) == 0) * check bit7 for IRQ7 and IRQ15 * * { * sysStrayIntCount++; * increment the counter * * return (ERROR); * } * } * * 00 e8 kk kk kk kk call _intEnt * tell kernel * 05 50 pushl %eax * save regs * 06 52 pushl %edx * 07 51 pushl %ecx * 08 68 pp pp pp pp pushl $_parameterBoi * push BOI param * 13 e8 rr rr rr rr call _routineBoi * call BOI routine * addl $4, %esp * cmpl $0, %eax * jne intConnectCode0 * 18 68 pp pp pp pp pushl $_parameter * push param * 23 e8 rr rr rr rr call _routine * call C routine * addl $4, %esp * 28 68 pp pp pp pp pushl $_parameterEoi * push EOI param * 33 e8 rr rr rr rr call _routineEoi * call EOI routine
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -