1 IRQ
When talking about the interrupted hardware environment, let's start with the famous IRQ signal. Each hardware device controller that can send an interrupt request has an output line named IRQ. All existing IRQ wires are connected to the input pins of a hardware circuit called the Programmable Interrupt Controller (PIC). The programmable interrupt controller performs the following actions:
1. Monitor the IRQ line and check the generated signal. If a signal is generated on one or more IRQ lines, select an IRQ line with a smaller pin number.
2. If a triggering signal appears on the IRQ line:
A) Convert the received triggering signal to the corresponding vector number (see the previous blog post ).
B) store this vector on an I/O port (0x20, 0x21) of the interrupt controller, allowing the CPU to read this vector through the data bus.
C) sending the triggering signal to the intr pin of the processor produces an interruption.
D) wait until the CPU writes the interrupt signal into an I/O port of the programmable interrupt controller to confirm it; when this happens, clear the intr line.
3. Return step 1.
You can selectively disable an 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. This feature is used by most interrupt handlers because it allows the interrupt handler to process the same type of IRQ one by one.
Here, we should note that selectively activating/disabling the IRQ line is different from the global blocking/unblocking of blocked interruptions mentioned in the previous blog. One is to program the pic, one is programming the CPU (assembly ). When the if flag of the eflags register is cleared to 0, each blocked interrupt released by the PIC is temporarily ignored by the CPU. CLI and STI Assembly commands clear and set the flag respectively.
The traditional PIC is connected by two 8259a external chips in cascade mode. Each chip can process up to 8 different IRQ input lines. Because the int output line of the PIC is connected to the irq2 pin of the main pic, the number of available IRQ lines is 15.
Starting with P3, Intel introduced an I/O advanced programmable controller (APIC) to replace the legacy 8259a Programmable Interrupt Controller. First, the new system retains the two cascading vintage PIC 8259a to support older operating systems. Second, the new 80 x CPU control units all contain a local APIC. This is not surprising, in order to support multi-CPU or multi-core systems. Each local APIC has a 32-bit register, an internal clock, a local scheduled device, and two additional IRQ lines lint0 and lint1 reserved for local APIC interruptions. All local apics are connected to the same external I/O APIC to form a multi-APIC system. The essence of APIC is the same as that of the traditional 8259a, but an additional layer of I/O APIC distributes External Interrupt requests on multiple CPUs.
2. Interrupt Descriptor Table
We mentioned earlier that the main purpose of the interrupt system is to change the execution sequence of the program. How to change it? That is, the process of calling the interrupt handler. Here we will introduce the Interrupt Descriptor Table. The Interrupt Descriptor Table (IDT) is a system table that is associated with every interrupt or exception vector, each vector has an entry address for the corresponding interrupt or exception handling program in the table. Before the kernel can interrupt, it must initialize the IDT properly.
IDT is a vector table. Each item in the table corresponds to an interrupt or exception vector. Each vector consists of 8 bytes. Therefore, up to 256x8 = 2048 bytes are required to store IDT, Which is exactly half a page. So where is this IDT? With the idtr CPU register, IDT can be located anywhere in the memory. The idtr Register specifies the linear base address of the IDT and its limit (maximum length ). Before interruption is allowed, the LIDT Assembly command must be used to initialize idtr.
IDT contains three types of descriptors, showing the meaning of 64-bit (8 bytes) in each descriptor. In particular ~ The value of the 43-bit type field indicates the types of the three descriptors.
These descriptors are:
Task Gate: When the interrupt signal occurs, the TSS selector of the process that replaces the current process must be stored in the task gate.
Interrupt Gate: contains the segment selection operator and the intra-segment offset of the interrupt or exception handling program. When control is transferred to an appropriate segment, the processor clears the if flag to disable future blocked interruptions.
Trap Gate: similar to the interrupt gate, the if flag is not modified when control is passed to an appropriate segment.
I will contact the previous blog post to emphasize that Linux uses the interrupt gate to handle interruptions and the trap gate to handle exceptions.
.
3. hardware handling of interruptions and exceptions
Now, with the basic concepts above, we can analyze how the CPU control unit handles interruptions and exceptions. We assume that the kernel has been initialized, so the CPU runs in protected mode. After an instruction is executed, the Cs and EIP pairs contain the Logical Address of the next instruction to be executed. Before processing the command, the control unit checks whether an interruption or exception has occurred while running the previous command. If an interruption or exception occurs, the Control Unit performs the following operations:
1. Determine the vector I (0 ≤ I ≤ 255) associated with the interrupt or exception ).
2. Read the I entry in the IDT table directed by the idtr register (in the following analysis, we assume that the IDT table item contains an interrupt door or a trap door ).
3. Obtain the base address of gdt from the GDTR register and search for it in gdt to read the segment descriptor identified by the selector in the IDT table. This descriptor specifies the base address of the segment where the interrupt or exception handling program is located.
4. Make sure that the interruption is initiated by the authorized (interrupted) source. First, compare the current privileged CPL (the lower two digits of the CS register) with the descriptor privileged DPL of the segment descriptor (stored in gdt). If CPL is smaller than DPL, A general protection exception occurs because the privileges of the interrupt handler cannot be lower than those of the program that causes the interruption. For programming exceptions, perform a further security check: Compare CPL with the DPL of the door descriptor in IDT. If DPL is smaller than CPL, a general protection exception is generated. This last check prevents user applications from accessing special traps or interrupting the door.
5. Check whether the privilege level changes, that is, whether CPL is different from the DPL of the selected segment descriptor. If yes, the control unit must start to use the stack associated with the new privileged level. Follow these steps:
I. Read the tr register to access the TSS segment of the running process.
Ii. Load SS and ESP registers with the correct values of stack segments and stack pointers related to the new feature level. These values can be found in TSS (see "task Status section" in Chapter 3)
Iii. Save SS and ESP values in the new stack. These values define the Logical Address of the stack associated with the old privileged level.
6. If the fault has occurred, use the abnormal command address to load the Cs and EIP registers so that the command can be executed again.
7. Save the content of eflags, Cs, and EIP in the stack.
8. If an exception generates a hardware error code, save it in the stack.
9. Load the Cs and EIP registers. Their values are the segment selection and offset fields of the I-gate descriptor in the IDT table. These values provide the Logical Address of the first instruction of the interrupt or exception handling program.
The last step of the control unit is to jump to the interrupt or exception handling program. In other words, after the interrupt signal is processed, the Command executed by the control unit is the first command of the selected processing program.
After an interrupt or exception is handled, the corresponding handler must generate an iret command to forward control to the interrupted process, which forces the control unit:
1. Load the CS, EIP, or eflags registers with the values stored in the stack. If a hardware error code has been pushed into the stack and on the EIP content, the hardware error code must be displayed before executing the iret command.
2. Check whether the CPL of the processing program is equal to the minimum two values in CS (this means that the interrupted process and the processing program run at the same privileged level ). If yes, iret terminates the execution; otherwise, it is transferred to the next step.
3. Load the SS and ESP registers from the stack, and therefore return to the stack associated with the old privilege level.
4. check the content of DS, es, FS, and GS segment registers. If one register contains a segment descriptor and Its DPL value is smaller than CPL, clear the corresponding segment register. The control unit is used to prohibit user-state programs (CPL = 3) from using the segment registers previously used by the kernel (DPL = 0 ). If these registers are not clear, malicious user-state programs may use them to access the kernel address space.