Interrupt and interrupt handling (2). interrupt handling
**
Book connection
**
(6): interrupt Context
When an interrupt processing program is executed, the kernel is in the interrupt context. the interrupt context cannot be sleep because there is no backup process, and the interrupt context has a strict time limit because it interrupts other code.
The Interrupt Processing Program stack setting is a configuration option. originally, the interrupt handler shared the kernel stack of the interrupted process. The size is two pages, that is, 8 KB On a 32-bit system and 16 KB On a 64-bit system. now every Interrupt Processing Program has its own interrupt stack, which is half the size, that is, 4 kb on 32-bit machines.
(7) Implementation of the interrupt handling mechanism
First, let's look at a route to interrupt from hardware to kernel:
In the kernel, the interrupted journey begins with a predefined entry point, which is similar to system calling that enters the kernel through a predefined exception handle. for each disconnection, the processor jumps to a unique position. in this way, the kernel can know the IRQ Number of the received interrupt. the initial entry point only saves this number in the stack and stores the value of the current Register (these values are interrupted tasks). Then, the kernel calls the function do_IRQ (). from here on, most of the interrupt processing code is written in C.
The fo_IRQ () statement is as follows:
unsigned int do_IRQ(struct pt_regs regs);
Because C's call convention is to place function parameters at the top of the stack, the pt_regs structure contains the value of the original register. these values were previously saved to the stack in the Assembly entry routine. the interrupt value can also be saved. so, do_IRQ () and extract it.
After the interrupt number is calculated, do_IRQ () responds to the received interrupt and disallows the interruption transmission on the interrupted line. on a normal PC, these operations are completed by mask_and_ack_8259A.
Next, do_IRQ () needs to ensure that there is a valid processing program on the interrupt line, and this program has been started, but is not currently executed. in this case, do_IRQ () will call handle_IRQ_event () to run the interrupt handler installed in the disconnection. next, let's take a look at the definition of the handle_IRQ_event () function, which is defined in kernel/irq/handler. c file.
/*** Handle_IRQ_event-irq action chain handler * @ irq: the interrupt number * @ action: the interrupt action chain for this irq ** Handles the action chain of an irq event ** handle_IRQ_event-irq operator chain handler * @ irq: interrupt Number * @ action: the operation chain of the interrupt ** processing an irq event */irqreturn_t handle_IRQ_event (unsigned int irq, struct irqaction * action) {irqreturn_t ret, retval = IRQ_NONE; unsigned int status = 0; if (! (Action-> flags & IRQF_DISABLED) local_irq_enable_in_hardirq (); do {trace_irq_handler_entry (irq, action); ret = action-> handler (irq, action-> dev_id ); trace_irq_handler_exit (irq, action, ret); switch (ret) {case IRQ_WAKE_THREAD:/** Set result to handled so the spurious check * does not trigger. ** set the return value to handled so that suspicious checks * will not be triggered. */ret = IRQ_HANDLED;/** Catch drivers which return WAKE_THREAD * Did not set up a thread function ** capture the driver whose return value is WAKE_THREAD, but * does not create a thread function */if (unlikely (! Action-> thread_fn) {warn_no_thread (irq, action); break;}/** Wake up the handler thread for this * action. in case the thread crashed and was * killed we just pretend that we handled the * interrupt. the hardirq handler above has * disabled the device interrupt, so no irq * storm is lurking. ** wake up the processing thread for this interrupt. in case the thread crashes and is killed, * we just pretend that we have handled the interrupt. the hard interrupt * mentioned above has disabled device interruption, thus eliminating the generation of irq. * **/if (likely (! Test_bit (IRQTF_DIED, & action-> thread_flags) {set_bit (IRQTF_RUNTHREAD, & action-> thread_flags); wake_up_process (action-> thread );} /* Fall through to add to randomness */case IRQ_HANDLED: status | = action-> flags; break; default: break;} retval | = ret; action = action-> next;} while (action); if (status & IRQF_SAMPLE_RANDOM) add_interrupt_randomness (irq); local_irq_disable (); return retval ;}
First, because the processor is not interrupted, to enable them here, you must specify the ir1_disabled flag during the processing program registration. in retrospect, ir1__disabled indicates that the handler must run without interruption. next, each potential processing program is executed in sequence in the loop. if this line is not shared, the loop will exit after the first execution. otherwise, all the processing programs will be executed. if the IRQF_SAMPLE_RANDOM flag is specified during registration, the add_interrupt_randomness () function is also called (). this function uses the interrupt interval to generate entropy for the random number generator. finally, the interruption is disabled (do_IRQ () is always expected to be interrupted), and the function returns. return to do_IRQ (). The function is cleaned up and returned to the initial entry point. Then, it jumps from the entry point to the ret_from_intr () function.
The ret_from_intr () routine is similar to the initial entry code and is written in assembly language. this routine checks whether rescheduling is pending. if rescheduling is pending and the kernel is returning the user space (that is, the user process is interrupted), schedule () is called. if the kernel is returning the kernel space (that is, the kernel process is interrupted), schedule will be called only when preempt_count is 0.
(8):/proc/interrupts
Orocfs is a virtual file system that only exists with the kernel memory and is installed in the/proc directory. kernel functions must be called to read and write files in procfs. These functions simulate reading or writing from real files. in this example, the/proc/interrupts file stores the interrupt-related statistics in the system. run the following command on the terminal:
cat /proc/interrupts
Let's take a look at the output:
For the proc file system, we have provided a more detailed introduction in my blog operating system.
(9): interrupt control
Linux provides a set of interfaces for operating the interrupt status on the machine. these interfaces provide us with the ability to disable the Interrupt System of the current processor, or block a disconnection from the entire machine. these routines are related to the architecture.
Local_irq_disable ();/* disable interruption */local_irq_enable ();
These two functions are usually implemented using a single assembly command. in fact, in X86, local_irq_disable () is only a cli command, while local_irq_enable () is only a sti command. cli and sti are Assembly calls for clear and set interrupt flag.
If interruption is disabled before local_irq_disable () is called, this routine brings potential risks. Similarly, the corresponding local_irq_enable () routine also has potential risks, because it will initiate unconditional activation interruptions, even though these interruptions are disabled at the beginning. therefore, we need a mechanism to restore the interruption to the previous state rather than simply disabling or activating it. the kernel is generally concerned about this because a given code path in the kernel can be achieved either when activation is interrupted or when interruption is disabled, this depends on the specific call chain. it is safer to save the state of the interrupted system before stopping the interruption. on the contrary, when preparing to activate the interrupt, you only need to reply the interrupt to their original state.
Unsigned long flags; local_irq_save (flags);/* forbidden interrupt */local_irq_restore (flags);/* the interrupt is restored to its original state */
These methods must at least be implemented in the form of macros. Therefore, flags parameters (these parameters must be defined as unsigned long type) are passed as values. this parameter contains the data of the specific architecture, that is, the status of the interrupted system. there must be at least one architecture that combines stack information with values (iSCSI). Therefore, flags cannot be passed to another function (especially it must reside in the same stack frame ). for this reason, the call to local_irq_save () and local_irq_restore () must be performed in the same function.
2: Disable the specified disconnection
In some cases, it is enough to disable a specific disconnection in the entire system. This is called masking out. Therefore, Linux provides four interfaces:
void disable_irq(unsigned int irq);void disable_irq_nosync(unsigned int irq);void enable_irq(unsigned int irq);void synchronize_irq(unsigned int irq);
The first two disallow the specified disconnection on the interrupt controller, that is, the delivery of a fixed interrupt to all processors in the system is prohibited. in addition, the disable_irq () function can return only after all the processing programs being executed are completed. therefore, the caller must not only ensure that a new interrupt is not transmitted on the specified line, but also ensure that all the processes that have started to be executed have exited. the diable_irq_nosygn () function does not wait until the execution of the currently interrupted processing program is completed.
The sygnchronize_irq () function waits for the exit of a specific interrupt handler. If the handler is being executed, the function must exit before returning.
The call to these functions can be nested. however, remember to call enable_irq () in each call of disable_irq_nosygn () on a specified interrupt line (). after the last call to enable_irq () is completed, the disconnection is re-activated. for example, if the disable_irq () function is called twice, the disconnection can be activated only after the second call of enable_irq.
3: the status of the interrupted System
Macro irqs_disable () is defined in
in_interrupt()in_irq()
The first macro is most useful: If the kernel is in any type of Interrupt Processing, it returns non-0, indicating that the kernel is executing the interrupt processing program at the moment, or is executing the lower half of the processing program.
Macro in_irq () returns non-0 only when the kernel is indeed executing the interrupt handler.
The following is a list of interrupt control methods.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.