About interrupt nesting: in the Linux kernel, if the driver is not specifically specified when applying for a registration interrupt, do_irq enables interrupt nesting when responding to an interrupt:
In the Linux kernel, if the driver is not specified when applying for a registration interrupt, do_irq enables the interrupt when responding to the interrupt, if the interrupt processing function of the driver is being executed and the interruption of the same device or different devices occurs, the new interrupt will be handled immediately or pending, wait until the current interrupt is processed.
In the 2.4 and 2.6 kernels, is there any difference about this.
Generally, the request is interrupted, that is, the SA_INTERRUPT flag is not used. If sharing is allowed, add SA_SHIRQ. if the entropy value can be provided for the kernel entropy pool (for example, the driver you write is an ide driver), add the SA_SAMPLE_RANDOM flag. This is a common process of interrupting requests. In this case, the kernel can be preemptible as long as the interrupt occurs, even if the kernel is executing other interrupt functions. There are two notes: First, because linux does not support the interrupt priority, any interruption can be preemptible, but the same type of interruption (that is, the interruption with the same disconnection is defined) there will be no preemption, and they will be called and executed in sequence when this type of interruption is executed. Second, there are some restrictions on the phrase "you can seize the kernel as long as there is an interruption, this is because the system is automatically disconnected when the system enters from the interrupt gate when the interrupt occurs (for x86 platform, the if position of the eflags register is 0), only when the interrupt function is executed (handle_IRQ_event) can be preemptible only after being interrupted. For interruptions of the same type, because the same idt table item is used, the state mark (IRQ_PENDING and IRQ_INPROGRESS) can be used to prevent the interruption of function execution of the same type (note: is to prevent handle_IRQ_event from being reimported, rather than do_IRQ function from being reimported), for different interruptions, you can freely nest. Therefore, the so-called interrupt nesting can be freely nested for different interruptions, but the same type of interruptions cannot be nested for execution.
The following briefly explains how to use the status flag to prevent re-entry of the same type of interruption:
When a certain type of interruption occurs for the first time, the IRQ_PENDING flag is assigned to the status bit of the idt table item, indicating that it is to be processed. Then, set the interrupt processing function action to null, and set its status to IRQ_INPROGRESS and IRQ_PENDING because its status does not have the IRQ_INPROGRESS flag (the first time, at the same time, assign the corresponding interrupt processing function pointer to the action (here is a key point. linux is a clever usage and will be explained later ). In this way, handle_IRQ_event can be successfully executed for interrupt processing. if there is an interruption of the same type in handle_IRQ_event, it will enter the do_IRQ function again, the IRQ_PENDING flag is added to the status bit, but the IRQ_INPROGRESS in the previous interrupt processing is not cleared, so the IRQ_PENDING flag cannot be cleared here, so the action is still null, in this way, the handle_IRQ_event function cannot be executed again. In this case, the handle_IRQ_event function is resumed. When handle_IRQ_event returns, check the IRQ_PENDING flag. If this flag exists, it indicates that handle_IRQ_event has been interrupted during execution and has not been processed. Therefore, the handle_IRQ_event function is executed cyclically again. Until the IRQ_PENDING flag does not exist.
The difference between 2.4 and 2.6 is that, in my opinion, the main reason is to enter do_IRQ in 2.6, there is an additional action to disable kernel preemption, at the same time, the IRQ_PER_CPU type is interrupted, and nothing else changes. This type of IRQ_PER_CPU interruption is mainly used to bind the interrupt to a specified cpu in the smp environment. For example, when ipi interruption is initialized in openpic_init in arch/ppc/syslib/open_pic.c.
In fact, interruption can be nested, but the same type of interruption cannot be nested, because the interruption occurs on IRQ and the IRQ is blocked during the response, that is, the IRQ interruption cannot be found.
At the same time, interruption is forbidden in the critical section of the kernel.
Do_IRQ may lose interrupt requests: the do_IRQ function judges whether the status is set with the IRQ_PENDING flag after the handle_IRQ_event function is executed to determine whether there are any interrupt requests in the same channel that have not been processed. However, this method can only determine whether there are any, rather than how many unprocessed unified channel interrupt requests. That is to say, if two or more interrupt requests in the same channel are generated during the first interrupt request to execute the handle_IRQ_event function, these interruptions will not come again, then, the handle_IRQ_event will only be executed once if the IRQ_PENDING flag is set by judging whether the status is correct and how many unhandled interruptions are unknown.
Isn't that a bug? No, as long as you know that there is an interruption and there is no processing, it is OK. Knowing One and knowing N is essentially the same. As peripherals, they should be able to handle situations where their interruptions are not handled.
It cannot be lost. there is a linked list in the structure of each interrupt descriptor, and the linked list stores the service example program.
Several important concepts and relationships used in interruptions:
I. Basic concepts
1.
|
Generated location |
Time of occurrence |
Time series |
Interrupted |
CPU external |
Random |
Asynchronous |
Exception |
CPU executing program |
After a command is terminated |
Synchronization |
2. the code that is interrupted or executed abnormally is not a process, but a kernel control path, which indicates the execution of the running process when the interruption occurs.
The interrupt handler is irrelevant to the running program.
The process that causes the Exception Handler is the current process when the exception handler is running.
II. Features
1. (1) as fast as possible
(2) it can be executed in nested mode, but the interruption of the same type cannot be nested.
(3) restrict the critical section as much as possible because the interruption is prohibited in the critical section.
2. most exceptions occur in the user state. page missing exceptions are the only exceptions that can be triggered by kernel state.
A page missing exception means that the process is switched. Therefore, the process is interrupted and never executed, which can lead to page missing operations.
3. the interrupt processing program runs in the kernel state.
When the interruption occurs in the user state, switch the user space stack of the process to the system space stack of the process. when switching, the kernel stack is empty.
The switch of stack space is not required when the interruption occurs in the kernel state.
III. classification
1. Categories of interruptions: blocked or unblocked interruptions
2. exception classification:
Category |
Solution to exceptions |
Example |
Fault |
The command will be re-executed |
Page missing exception handling program |
Traps |
The execution starts from the next command. |
Debug program |
Abort an exception |
Force affected process termination |
A serious error occurred. |
IV. IRQ
1. the hardware device controller sends an interrupt to the CPU through the IRQ line. you can disable an IRQ line to shield the interrupt.
2. prohibited interruptions will not be lost. after IRQ is activated, the interruption will be sent to the CPU
3. activate/disable IRQ! = Globally blocked/unblocked interruptions
You can selectively disable each IRQ line. Therefore, you can program the PIC to disable IRQ, that is, you can tell the PIC to stop publishing interruptions to the given IRQ line, or to activate them. The prohibited interruptions cannot be lost. once they are activated, the PIC sends them to the CPU. This feature is used by most interrupt handlers because it allows the interrupt handler to process the same type of IRQ one by one.
Assume that the CPU has an active IRQ line. A hardware device appears on this IRQ thread, and multiple APIC systems choose our CPU to handle interruptions. Before the CPU response is interrupted, the IRQ line is blocked by another CPU. as a result, the IRQ_DISABLED flag is set. Then, our CPU starts to process the suspended interrupt. Therefore, the do_IRQ () function responds to the interrupt and then returns, but does not execute the interrupt service routine because it finds that the IRQ_DISABLED flag has been set, therefore, the interruption occurs before the IRQ line is disabled.
To cope with this situation, the kernel is used to activate the enable_irq () function of the IRQ line first to check whether there is a loss of interruption. If yes, this function forces the hardware to cause a loss of interruption again.
The biggest difference between them is that the upper half cannot be interrupted, while the lower half can be interrupted.
5. interrupt descriptor table IDT
1. Basic concepts
The interrupt descriptor table is a system table that is associated with every interrupt or exception vector. each vector has the corresponding interrupt or exception handler entry address in the table.
IDT must be properly initialized before interruption is permitted
TSS can only be located in GDT, and IDT can be located anywhere in memory
2. interrupt descriptor
Interrupt Descriptor provided by hardware:
(1) task gate: When the interruption signal occurs, the TSS identifier of the process that replaces the current process must be stored in the task gate.
(2) interrupt door: contains the segment separator and the intra-segment offset of the interrupt handler
(3) trap door: The only difference with the interruption door is that after the interruption door enters the service program, it is automatically disconnected, and the access through the trap door to the service program is not automatically disconnected.
Interrupt descriptor used in Linux:
Type of the interrupt descriptor |
Whether the user mode can be accessed |
User-mode access |
Programs that can be activated |
Broken door |
No |
|
All Linux interrupt handlers |
System gate |
Yes |
Into, bound, int $0x80 |
Three Linux exception handlers with vector numbers 4, 5, and 128 |
System interrupt door |
Yes |
Int 3 |
Exception handling program related to Vector 3 |
Trap Door |
No |
|
Most Linux exception handling programs |
Task gate |
No |
|
Linux Double fault exception handling program |
In Linux, system doors, system interrupt doors, and trap doors all use hardware traps.
Linux uses the interrupt gate to handle interruptions, and uses the trap gate to handle exceptions
Double fault is the only exception handled by a task.
3. relationship between interrupt vectors and interruptions and exceptions
(1) Each interrupt and exception are identified by a number between 0 and, which is the interrupt vector in 1.
(2) There are about 20 exceptions. the kernel assigns an interrupt/exception vector for each exception, which is 0-19.
(3) 0x80 is the interrupt vector of the system call.
(4) 32-is the interrupt vector for kernel interrupt allocation. However, the 224 interrupt vectors are obviously insufficient. Therefore, the system sets a queue for each interrupt vector and mounts the interrupt service program to the corresponding queue based on the interrupt vectors used by each interrupt source. When an interruption occurs, first execute a section of the total service program corresponding to the interrupt vector, and then find a specific interrupt service program in the queue to which the source device number belongs.
4. relationship between the interrupt vector, the total service program corresponding to the interrupt vector, and the interrupt service program of an interrupt Source:
(1) irq_desc is the interrupt vector descriptor queue (the interrupt descriptor is an INT item, and the interrupt vector descriptor is a data structure used to describe service programs related to the interrupt vector)
(2) irq_desc_t is the data structure of the interrupt vector descriptor.
(3) irqaction is the descriptor of a specific interrupt service program attached to an interrupt vector, forming a queue
(4) hw_irq_controller is the total service program of this interrupt vector.
6. IDT initialization
1. two initialization times
|
Running mode |
Initial value |
User |
First time |
Real mode |
Empty handler |
BIOS routine |
Second |
Protection mode |
Meaningful interrupt handler or exception handler |
Linux |
2. at the beginning of the initialization of the IDT table, each interrupt processing queue is empty. in this case, even if the interrupt is enabled and a peripheral interrupt occurs, the actual service is not available, because no specific interrupt handler is executed.
The real interrupt service will only occur after the discontinuing handler ISR is attached to an interrupt request queue by the initialization program of a specific device.
3. the IDT must be properly initialized before interruption is permitted.
7. activation interruption or exception (the following content is automatically completed by the hardware)
1. determine the interrupt vector number associated with the interrupt or exception
Interrupt: the controller of the hardware device sends a signal to the CPU through IRQ. the interrupt controller converts the received signal to the interrupt vector No. I.
Exception: If an exception occurs when a software instruction is sent or generated, the CPU category is incorrectly classified. This Category number is the interrupt vector.
2. IDT entry I -----> segment selector -----> segment descriptor -----> Segment base address
3. IDT I-> offset
4. Segment base address + offset -----> address of the first instruction of the interrupt handler
5. Save the EFLAGS, CS, and EIP content in the stack.
6. if an exception generates an error code, save it in the stack.
7. load CS and EIP, whose values are 2-segment selector and 4-offset. the address of the first instruction of the interrupt or exception handling program can be obtained from these two registers.
8. find the first instruction of the interrupt or exception handling program and jump to the instruction process.
1. interrupted
(1) The IRQ value is saved in the kernel stack of the current process. why is it different from the system call number?-n is saved
(2) save the register value in the kernel stack of the current process: SAVE_ALL
EFLAGS, CS, EIP, SS, and ESP are not included because they are automatically saved by the control unit (see 7-7)
(3) store the top stack address in EAX
(4) load the user segment selection character to DS and ES
(5) Call do_IRQ () and save the address in CS and EIP (see 7-7)
(6) a response is being sent to the PIC (Interrupt Controller) of the IRQ line service, which will allow the PIC to issue further interruptions.
(7) ISR of all devices that share this IRQ (the total service program is called IRQ, and the specific service program of a device is called ISR)
(8) jump to the ret_from_intr () address and terminate
(6) (7) (8) are all called in (5), see 10
2. Exceptions
(1) if an exception occurs, the control unit does not push an error code out of the stack (see 7-6), then it is pushed into a null value.
The error code of this number is not where the normal error code should be. The Following-step is to adjust it to the position where it should be
(3) push the address of the exception handling program to the stack.
(4) save the registers that may be used for exception handling to the stack.
(5) copy the hardware error code at ESP + 36 in the stack to EDX and store-1 in the stack.
(6) load the address of the exception handler stored in the ESP + 32 position in the stack into EDI, and write the ES value to this position in the stack.
(7) copy the stack to EAX as the top of the stack
(8) load the user segment selection character to DS and ES
(9) exception handling program for calling an address in EDI
9. process returned from the interrupt or exception handling program
1. jump to the entry point for the returned code
(1) interrupt ret_from_intr ()
(2) exception: ret_from_exception ()
2. load the current thread descriptor address to EBP
3. determine whether to return to the user state or kernel state based on CS and EFLAGS in the stack.
4. if a process scheduling request exists
5. terminate the control by executing the iret command, and the interrupted program starts to execute again.
10. IRQ
1. a response is being sent to the PIC (Interrupt Controller) of the IRQ line service, which will allow the PIC to issue further interruptions
2. if any of the following conditions occurs
(1) the corresponding IRQ line is forbidden
(2) another CPU can normally handle such interruptions.
(3) no relevant ISR
3. execute ISR for all devices that share this IRQ
4. check whether there is any delayed function waiting for execution. if there is do_softirq ()
5. ret_from_intr ()
11. service interruption routine
An ISR is used to perform operations on a specific device. When the interrupt handler must execute ISR, it calls the hand_IRQ_event () function.
12. dynamic allocation of IRQ lines
The corresponding driver calls request_irq () before activating a device that is ready to use the IRQ line (). This function creates a new irqaction function and initializes it with the parameter value. Then, call the setup_irq () function to insert the descriptor to the appropriate IRQ linked list. If setup_irq () returns an error code, the device driver aborts the operation, which means that the IRQ line is already used by another device and the device cannot interrupt sharing. When the device operation ends, the driver calls the free_irq () function to delete the descriptor from the IRQ linked list and release the corresponding memory zone.
Request_irq ()
Free_irq ()
1. Linux classifies the operations to be executed immediately following the interruption into three types
|
Features |
Solution |
Example |
Category 1 |
Urgent |
Immediate execution if interruption is blocked |
Modify the data structure accessed by both devices and processors |
Category 2 |
Non-urgent |
Immediate execution upon interruption |
Modify the data structure that only the processor can access (for example, press the next key to read the scan code) |
Category 3 |
Non-urgent and delayed |
Executed by independent functions |
Copy the buffer kernel to the address space of a process. |
2. extract the delayed interrupt from the interrupt handler and execute it by independent functions, which helps keep the kernel in a short response time.
3. Linux2.6 uses the deletable function and work queue to process the deletable interrupt. Both are kernel functions.
II. delayable functions
1. delayed functions include soft interrupt and tasklet. tasklet is implemented on soft interrupt.
Tasklet is the preferred method for implementing delayable functions in the I/O driver.
Tasklet is built on the two soft interruptions: HI_SOFTIRQ and TASKLET_SOFTIRQ.
Several tasklets can be associated with the same soft break. each tasklet executes its own function.
|
Allocation method |
Concurrency |
Reentrant |
Soft interrupt |
Static allocation during compilation |
Can run concurrently on multiple CPUs |
It must be reentrant and use spin locks explicitly to protect its data structure |
Tasklet |
Dynamic allocation during runtime |
Tasklet of the same type is always executed serially. Different types of tasklet can be concurrently executed on several CPUs |
Not necessarily reentrant |
2. a delayable function activated by a given CPU must be executed on the same CPU.
The kernel cannot be preemptible when a function can be delayed, because the process from one CPU to another needs to be suspended.
3. Comparison of data structures used by interruptions and soft interruptions
|
Interrupted |
Soft interrupt |
Interrupt vector number descriptor |
Irq_desc [interrupt vector number] |
Softirq_vec [soft interrupt number] |
Interrupt Request Register |
Interrupt Request Register |
_ Softirq_active |
Interrupt shield register |
Interrupt shield register |
_ Soft_mask |
Interrupt handling program |
Do_handler_name |
Bh []: 32 |
Description of the interrupt handler |
Irqaction |
Softirq_action |
Initialization of the interrupt mechanism |
Trap_init (): exception initialization Init_IRQ (): interrupt initialization |
Softirq_action |
Initialize the interrupt request queue |
Init_ISA_irqs () |
Open_softirq |
The interrupt handler is associated with the interrupt request queue |
Request_irq () |
Init_bh () |
Execution interrupted |
Do_IRQ () |
Do_softirq |
4. activate the delayable function
(1) activate soft interrupt
A. set the soft interrupt to the suspended state, and periodically check the soft interrupt in the suspended state. If yes, call do_softirq ()
B. generally, check the suspended soft interrupt at the following points.. call local_bh_enable () to activate B. when do_IRQ () completes the I/O interrupt processing and is about to exit c. d. else. I don't think it's important.
(2) activate tasklet
A. add the defined descriptor to the linked list pointed to by tasklet_vec. When tasklet_action () is called, each tasklet descriptor in the queue is processed in sequence, and the linked list pointed to by tasklet_vec is cleared.
B. Each tasklet activation triggers at most one execution of the tasklet function, unless the tasklet function re-activates itself.
3. work queue
1. they allow kernel functions to be activated and later executed by a special kernel thread called a worker thread
If the system has n CPUs, n workers are created, but only one working queue is created.
2. differences between a work queue and a delayable function:
The delayable function is interrupted in the context, while the work queue is running in the context of the process.
The delayable function cannot be blocked, and the work queue can execute the blocking function.
When a delayable function is executed, there cannot be any running process. the Function in the work queue is executed by the kernel thread and does not access the user-state address space.
3. activation of the work queue
Insert the descriptor of the function to be executed into the work queue.
The worker waits for the function to be inserted into the queue. after being awakened, the function descriptor is removed and executed.
The working queue function can be blocked, and the worker thread can sleep or move another CPU
All in all:
When an interruption occurs,