Today we will talk about interruptions of x86 (-64) processors. More under the cut.
Interrupts are like a signal to the processor that it is necessary to interrupt the execution (they are therefore called interrupts) of the current code and urgently do what is indicated in the handler.
IDT
All interrupt handler addresses are stored in the
IDT . This is a table that stores 256 (more or less, but most of the values are simply ignored) cells (interrupt vectors) with the type and attributes of the interrupt, one simply zero value, the address of the interrupt handler and the code selector in GDT or LDT, which will use this interrupt vector. Now a little about the type and attributes.
Interrupt type and attributes occupy 8 bits. The first 4 bits are of the type:
- 0b0101: 32-bit gate of the task, when such an interrupt occurs, a hardware switch of the task occurs (yes, there is such a thing, but it has not been used for a long time)
- 0b0110: 16-bit interrupt gate
- 0b0111: trap'a 16-bit gate (I don’t know how to translate it into Russian, sorry)
- 0b1110: 32-bit interrupt gate
- 0b1111: 32-bit gate trap'a
Next are the attributes. The first attribute is 1 bit, which is set to 0 for interrupt gates and 1 to the rest. Next comes the descriptor privilege level - 2 bits, which sets the minimum privilege level for the interrupt call, and 1 bit, set to 0 for unused interrupts.
Now how the processor causes handlers.
Suppose that you called the instruction
int 0
in assembler. This will signal the processor to cause an interrupt of 0, if possible. Here is a sequence of actions that occur during this.
- Search vector number 0 in IDT.
- Comparison of the level of privileges of the descriptor and the current level of privileges of the processor.
- If the current privilege level of the processor is lower than the privilege level of the descriptor, then simply cause a general protection error and not cause an interrupt.
- The return address, register (E) FLAGS and other information are saved.
- There is a transition to the address specified in the vector №0 IDT.
- After executing the handler, the
iret
instruction returns control to the interrupted code.
Exceptions
There are also interrupts that are generated by the processor itself under certain circumstances -
exceptions . Here is a list of them with brief descriptions:
- Division by zero. It is generated when, in fact, division by zero.
- Debug exception Cannot be generated by itself, it is used for debugging itself.
- Nonmaskable interrupt It is generated when RAM errors and unrecoverable hardware errors. They cannot be masked with the help of the PIC (Programmable Interrupt Controller - Programmable Interrupt Controller), since it goes directly to the processor, bypassing the PIC, but you can simply turn it off.
- Breakpoint. It is also used for debugging, because its opcode occupies only 1 byte, unlike the rest of INT N. It was reassigned by DOS debuggers for its own purposes.
- Overflow. Generated by an
INTO
instruction if the overflow bit is enabled in (E) FLAGS. - Going beyond. Generated upon error of the BOUND instruction.
- Invalid opcode. Generated when attempting to execute an invalid opcode.
- Device unavailable. Now not used, generated when trying to use floating point operations on processors without FPU.
- Double fault. It is difficult to translate the name. The error is unrecoverable, occurs when it is impossible to call an exception handler.
- Coprocessor segment overflow. No longer used.
- Invalid TSS. The task status segment is set incorrectly.
- The segment is missing. Occurs when trying to load a segment with the Present bit == 0.
- Error stack segment. Occurs when trying to load a segment with the Present == 0 bit or stack overflow.
- General error of protection. It is generated in a very large number of cases, among them there is a segment error, an attempt to execute the instruction without the necessary rights, a record where it is not necessary, an attempt to access the zero GDT descriptor, and much more.
- Page error. Occurs when reading or writing to a non-existent page of memory, trying to access data without the necessary permissions or another.
- Floating point error. Occurs when the FWAIT or WAIT instruction is executed with bit No. 5 in CR0 == 0.
- Error checking for alignment. Occurs only in the third processor privilege ring, if this error is, of course, enabled.
- Error while checking the machine. Generated by the processor when detecting "iron" errors.
- SIMD floating point exception. Generated on errors with 128-bit floating point numbers.
- Virtualization error.
- Security error
- Triple mistake. In fact, the exception is not, it is not even an interruption. Occurs when you cannot call Double Fault. Causes the computer to immediately restart.
')
IRQ
There is a special type of interrupt -
IRQ (Interrupt ReQuest) , or hardware interrupts, but for brevity I'll call them just IRQ. Technically, they are almost the same as any other interrupts, but they are not generated by the processor or the code itself, but by devices connected to the computer. For example, IRQ # 0 generates a PIT (timer with a programmable interval), IRQ 1 is generated when you press a key on the keyboard, and IRQ 12 - when operating with a PS / 2 mouse.
Software interrupts
There are also so-called
software interrupts . They, as the name implies, the program should call itself - no one calls them for it. These are, for example, system calls in some systems. In Linux, for example, they hang on the vector 0x80. In many hobby OS, they also hang on the vector 0x80. Now, a little ad-libbing - I think that syscalls are made as interrupts because 1) they are so very easy to call, 2) they can be called from any code running in the OS — the IDT is one for the whole system.
Info taken from OSDev Wiki .