From IRQ to IRQL (APIC Edition)
Sobeit
In fact, the old PIC has been eliminated very early, and it is an apic. Since the APIC can be compatible with the PIC, we see the PIC we have seen on many single-processor systems is actually a compatible PIC mode of the APIC. APIC is primarily applied to multiprocessor operating systems, to solve the IRQ minimum and processor interrupts, of course, single processor operating systems can also use APIC (not analog PIC). APIC's HAL and PIC have a great difference. One of the highlighted features is that the APIC's HAL does not have to virtualize an interrupt controller like the PIC's HAL. The concept of IRQL has been able to be supported by an interrupt vector. In fact, because of the APIC, IRQL's implementation in APIC HAL is much simpler than the PIC HAL.
Now let's briefly introduce the structure of the APIC (for detailed description of APIC, please refer to IA-32 INEL Architecture Software Developer's Manual Volume 3 Chapter 8 "). The entire APIC system consists of local APIC, IO APIC, and APIC serial bus (after Pentium 4 and Xeon, the APIC bus is placed in the system bus). A local APIC is integrated in each processor, and IO APIC is part of the system chipset, and the APIC bus is responsible for connecting to IO APICs and various local APICs. Local APIC receives local interrupts such as clock interrupts generated by the processor, and interrupts between the processor generated, and receive messages from the IO APIC from the APIC Serial bus; IO APIC is responsible for receiving all external hardware interrupts, and Translation into a message Select the processor issued to the received interrupt, and the interrupt message interrupt from the local APIC reception processor.
Like the PIC, the method of controlling the local APIC and IO APIC is to read the associated register in the unit. However, the PIC is not the same, Intel maps the registers of the local APIC and IO APICs to the physical address space, and the local APIC default mapped to the physical address 0xffe00000, IO APIC default mapped to physical address 0xFEC00000. Windows Hal further maps the local APIC to the virtual address 0xffe0000, maps the IO APIC to the virtual address 0xffd06000, that is, the reading and writing of the address is actually reading and writing of the register, and several important storage in the local APIC has an EOI register. , Task Priority Register (TPR), Processor Priority Register (PPR), Interrupt Command Register (ICR, 64-bit), Interrupt Request Register (IRR, 256 Bits, One Volume 1), Interrupt in Service Register ( ISR, 256-bit), etc. Several important registers in the IO APIC have version registers, I / O Register Select Registers, I / O Window Registers (Use Address I / O Register Select Registers to Access I / O Register I / O Register, Access I / O Window Register is access to selected registers) It is also important to have an IO redirect table, each entry is a 64-bit register, including related bits of vector and target mode, transmission mode, etc., each entry connection A number of IRQ lines, the number of items with the version of the processor, and 24 items on Pentium 4. The number of entry is stored in the [16:23] bit of the IO APIC version register. The APIC system supports 255 interrupt vectors, but Intel retains 0-15 vectors, and the vector available is 16-255. And introduce a concept called task priority = interrupt vector / 16, because 16 vector, the available priority is 2-15. When setting the task priority register TPR in the local APIC with a specified priority, all priorities below the TPR are shielded, is it very similar to the mechanism of IRQL? In fact, the IRQL mechanism in Apic HAL is also achieved by this task priority register. The same task priority includes 16 interrupt vectors that can further finely grade the priority of interrupts.
Although HalbeginsystemInterrupt is still an IRQL mechanism engine, because there is APIC support, it is much more simpler than the functionality of IRQL than the corresponding functionality in PIC HAL. HalbeginsystemInterrupt Gets the IRQL corresponding task priority by using IRQL to get the task priority of the IRQL, with this priority setting task priority register TPR, and the original task priority / 16 in the TPR is used as an index to get the corresponding correspondence in the HalpvectorToiRQL array. The original IRQL then returns. If IRQL is upgraded from below Dispatch_level to higher than DISPATCH_LEVEL, it is also necessary to set KPCR 0x95 (0xFFDFF095) to dispatch_level (0x2), indicating that the IRQL is increased from DISPATCH_LEVEL below. HalendsystemInterruPt transmits 0 to the EOI registration of the local APIC, indicating that the interrupt is completed, and new interrupts can be received. It is also necessary to determine if the IRQL to be reduced is smaller than the dispatch_level. If it is less than, the KPCR 0x96 (0xFFDFF096) is further determined, if the position is set, there is a DPC interrupt waiting (at IRQL above Dispatch_level being triggered, then waiting until IRQL drops below dispatch_level, then the KPCR 0x95 and KPCR 0x96 clearance is then called the KidispatchInterRupt response to the DPC soft interrupt. Otherwise, the job is the same as the HalbeginsystemInterrupt: convert the IRQL to the task priority to set the TRP, and turn the long task priority to IRQL returns. KfraiseiRQL, KfloweriRQL and other functions are also like this, modify the TPR to the current IRQL to task priority, and turn the value of the original TPR into the original IRQL and return. The generation of soft interrupts also has an APIC support. APIC can generate a soft interrupt by generating an interrupt between a handleable processor, because the vector can specify the interrupt, so the soft interrupt can distinguish the priority level, such as APC_LEVEL DISPATCH_LEVEL. Producing a soft-interrupt function or a HALREQUESTSOFTWAREINTERRUPT, which will first determine if the KPCR 0x95 is the same as the soft interrupt IRQL to be generated. If it is, set KPCR 0x96 and returns, indicating that IRQL is greater than dispatch_level, so the DPC interrupt is not processed. Otherwise, the corresponding task priority is taken from Halpirqltotprha by the IRQL to which the soft interrupt to be generated is removed from the Halpirqltotprha, and the 0x4000 is indicated as the fixed processing interrupt in which it is, and the upper 32 bit of the interrupt command register ICW is set, and then read Take the lower 32 bits of the interrupt command register ICW to be 0x1000, determine that the interrupt message has been returned, and the soft interrupt has been generated. It is worth noting that there is no HalendsoftwareIinterRupt this in Apic HAL. HAL provides a fixed interrupt vector for soft interrupted IRQL: #define ZERO_VECTOR 0x00 // IRQL 00
#define apc_vector 0x3d // IRQL 01
#define dpc_vector 0x41 // IRQL 02
#define APIC_GENERIC_VECTOR 0XC1 // IRQL 27
#define apic_clock_vector 0xd1 // IRQL 28
#define apic_synch_vector 0xd1 // IRQL 28 # define apic_ipi_vector 0xe1 // IRQL 29
#define powerfail_vector 0xef // IRQL 30
#define apic_profile_vector 0xfd // IRQL 31
Take a look at some important data:
This is the IO APIC redirection table I have written by the code.
Redirect Table INDEX: 0x17
Redirect Table [0]: FF
Redirect Table [1]: B3
Redirect Table [2]: FF
Redirect Table [3]: 51
Redirect Table [4]: FF
Redirect Table [5]: FF
Redirect Table [6]: 62
Redirect Table [7]: FF
Redirect Table [8]: D1
Redirect Table [9]: B1
Redirect Table [A]: FF
Redirect Table [B]: FF
Redirect Table [C]: 52
Redirect Table [D]: FF
Redirect Table [E]: FF
Redirect Table [F]: 92
Redirect Table [10]: FF
Redirect Table [11]: A3
Redirect Table [12]: 83
Redirect Table [13]: 93
Redirect Table [14]: FF
Redirect Table [15]: FF
Redirect Table [16]: FF
Redirect Table [17]: FF
This is a registered vector in the IDT table:
1F: 80064908 (HAL! HalpapicsPuriousservice)
37: 800640B8 (HAL! PICSPURIOSERVICE37)
3D: 80065254 (Hal! Halpapcinterrupt)
41: 800650C8 (Hal! HalpdispatchInterrupt)
50: 80064190 (Hal! HalpapicrebootService)
51: 817f59e4
(Vector: 51, IRQL: 4, SyncIRQL: 4, Connected: true, no: 0, Sharevector: False, Mode: Latch, ISR: Serial! Serialcisrsw (F3C607C7))
52: 817f5044
(Vector: 52, IRQL: 4, SyncIRQL: A, Connected: true, no: 0, Sharevector: False, Mode: Latch, ISR: i8042PRT! I8042MouseInterruptService (F3C57A2C))
83: 817D2D44
(Vector: 83, Irql: 7, SyncIRQL: 7, Connected: True, No: 0, Sharevector: true, mode: LevelSensitive, ISR: NDIS! NDISMISR (BFF1B794))
92: 81821384
(Vector: 92, Irql: 8, SyncIRQL: 8, Connected: true, no: 0, Sharevector: false, mode: latched, isr: atapi! Scsiportinterrupt (bff892be))
93: 8185ed64 (Vector: 93, IRQL: 8, SyncIRQL: 8, Connected: true, no: 0, Sharevector: true, mode: levelSensitive, ISR: UHCD! UHCD_INTERRUPTSERVICE (F3F0253e))
A3: 8186CDC4
(Vector: A3, IRQL: 9, SYNCIRQL: 9, Connected: True, No: 0, Sharevector: True, Mode: LevelSensitive, ISR: SCSIPORT! SCSIPORTINTERRUPT (BFF719F0))
B1: 818902E4
(Vector: B1, IRQL: A, SynciRQL: A, Connected: True, No: 0, Sharevector: True, Mode: LevelSensitive, ISR: ACPI! ACPIINTERRUPTSERVICEROUTINE (Bffe14b4))
B3: 81881664
(Vector: B3, IRQL: A, SynciRQL: A, Connected: true, no: 0, Sharevector: False, Mode: Latch, ISR: i8042PRT! I8042keyboardInterruptService (F3c51918))
C1: 800642FC (HAL! HALPBROADCASTCALLSERVICE)
D1: 80063964 (HAL! HALPCLOCKInterrupt)
E1: 80064858 (Hal! HalpipiHandler)
E3: 800645D4 (Hal! HalplocalapicerRorService)
FD: 80064D64 (HAL! HALPPROFILINTERRUPT)
Fe: 80064EEC (Hal! Halpperfinterrupt)
Like the A3, B1 This type of output content is the interrupt vector registered by the hardware, but like D1, E3 This output content is to register for the interrupt vector used in the HAL inside, and the local APIC interrupt vector.
This is a few important arrays:
HalvectorToirql (This array is in vector with an index:
8006A304 00 FF FF 01 02 04 05 06-07 08 09 0A 1B 1C 1D 1E
Halpirqltotpr:
8006A1E4 00 3D 41 41 51 61 71 81-91 A1 B1 B1 B1 B1 B1
8006A1F4 B1 B1 B1 B1 B1 B1 B1 B1-B1 B1 B1 C1 D1 E1 EF FF
Halpintitovector:
8006ADA0 00 B3 61 51 A2 B2 62 91-A1 B1 71 81 52 82 72 92
8006ADB0 00 A3 83 93 00 00 00 00 00 00 00 00 00
Halvectortio:
8006A204 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A214 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A224 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A234 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A244 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A254 FF 03 0C FF FF FF FF-FF FF FF FF FF FF FF
8006A264 FF 02 06 FF FF FF FF FF-FF FF FF FF FF FF FF
8006A274 FF 0A 0E FF FF FF FF-FF FF FF FF FF FF FF8006A284 FF 0B 0D 12 FF FF FF-FF FF FF FF FF FF FF
8006A294 FF 07 0F 13 FF FF FF-FF FF FF FF FF FF FF
8006A2A4 FF 08 04 11 FF FF FF FF-FF FF FF FF FF FF FF
8006A2B4 FF 09 05 01 FF FF FF FF-FF FF FF FF FF FF FF
8006A2C4 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A2D4 FF 08 FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A2E4 FF FF FF FF FF FF FF-FF FF FF FF FF FF FF
8006A2F4 FF FF FF FF FF FF FF-FF FF FF FF FF FF
vbucket:
8006AE30 02 02 02 03 03 03 03
For example, the IRQ of SCSI Controller in my virtual machine is 17 (note, it has been greater than 16), to find the 17th item in the redirect table, get the interrupt vector is 0xA3, then look at the IDT, 0xA3 correspondence The routine is SCSIPORT! SCSIPORTINTERRUPT.
VBucket array dry? It is used to assign new vectors. The allocation algorithm is very simple. When you want to assign a new vector, you can search the minimum number of numbers from right to left from right to left, and the number is index in Vbucket, and the new vector is (0x50 index * 16 i). 1), the new vector corresponds to (4 i 1), while adding the i plus 1, I is not greater than 16. This vbucket given, I = 2, index = 2 when the next calculation is calculated. However, these vectors for hardware call HalpGetSystemInterRuptVector when IO system initialize, and then register the routines that registered with the vector position registered in the IDT via IOCONNECTINTERRUPT as an interrupt handler. It is not that each registered vector will correspond to the interrupt handler, and the 0xA1, 0XA2, 0xb1, etc., which are given above, no correspondence.
The IRQL mechanism provides a lot of convenience for kernel synchronization, which is also facilitated the driver developer hidden the underlying interrupt mechanism, which is also convenient for driving developers' kernel synchronization. LINUX has been introduced from the 2.5 kernel and the task queue and other mechanisms such as the mechanism of the WINDOWS.
I finally finished the test, liberated, huh, huh. There is still a lot of writable, just don't have time to analyze. In the 64-bit system in the future, the APIC is soon replaced by SAPIC based on the message-based multi-power mechanism.