CPU如何找到ISR并区分设备
我应该首先分享我所知道的一切——那是完全混乱的。关于这个主题有几个不同的问题,所以请不要生气:)。
1) 为了查找ISR,CPU 被提供了一个中断号。在 x86 机器(286/386 及更高版本)中,有一个 IVT,其中包含 ISR;每个条目的大小为 4 字节。所以我们需要将中断号乘以4来找到ISR。所以第一个问题是 - 我对 CPU 接收中断的机制完全感到困惑。要引发中断,设备首先应探测 IRQ - 然后怎么办?中断号“在 IRQ 上”传送至 CPU?我还读到类似 device put ISR address on databus 的内容;那是什么?覆盖 ISR 的设备是什么概念?有人可以告诉我一些 CPU 轮询中断的示例设备吗?它在哪里为他们找到情监侦?
2)如果两个设备共享一个IRQ(这很有可能),它们之间的CPU有何不同?如果两个设备同时发出相同优先级的中断怎么办?我知道会有相同类型和低优先级中断的屏蔽 - 但这种通信如何在 CPU 和设备控制器之间发生?我研究了PIC和APIC对于这个问题的作用,但无法理解。
感谢您的阅读。 非常感谢您的回答。
I should first share all what I know - and that is complete chaos. There are several different questions on the topic, so please don't get irritated :).
1) To find an ISR, CPU is provided with a interrupt number. In x86 machines (286/386 and above) there is a IVT with ISRs in it; each entry of 4 bytes in size. So we need to multiply interrupt number by 4 to find the ISR. So first bunch of questions is - I am completely confused in mechanism of CPU receiving the interrupt. To raise an interrupt, firstly device shall probe for IRQ - then what ? The interrupt number travels "on IRQ" towards CPU? I also read something like device putting ISR address on data bus ; whats that then ? What is the concept of devices overriding the ISR. Can somebody tell me few example devices where CPU polls for interrupts? And where does it finds ISR for them ?
2) If two devices share an IRQ (which is very much possible), how does CPU differs amongst them ? What if both devices raise an interrupt of same priority simultaneously. I got to know there will be masking of same type and low priority interrupts - but how this communication happens between CPU and device controller? I studied the role of PIC and APIC for this problem, but could not understand.
Thanks for reading.
Thank you very much for answering.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
CPU 不会轮询中断,至少在软件意义上不会。对于软件来说,中断是异步事件。
所发生的情况是,CPU 内的硬件识别中断请求(中断线上的电输入),并作为响应,搁置事件的正常执行以响应中断。在大多数现代 CPU 中,接下来发生的情况由特定于 CPU 类型的硬件握手决定,但大多数 CPU 都会从中断设备接收某种类型的数字。该数字可以是 8 位或 32 位或其他任何值,具体取决于 CPU 的设计。然后CPU使用该中断号索引中断向量表,找到开始执行中断服务程序的地址。一旦确定了该地址(并且当前执行上下文被安全地保存到堆栈中),CPU 就开始执行 ISR。
当两个设备共享一条中断请求线时,它们可以通过在握手过程中返回不同的中断号来导致不同的 ISR 运行。如果有足够的可用向量数,每个中断设备都可以使用自己的中断向量。
但是,两个设备甚至可以共享一条中断请求线和一个中断向量,前提是共享的 ISR 足够聪明,能够返回给定中断的所有可能源,并检查状态寄存器以了解哪个设备请求了服务。
更详细一点
假设您有一个由 CPU、中断控制器和中断设备组成的系统。在过去,这些都是独立的物理设备,但现在这三个设备甚至可能驻留在同一芯片中,但所有信号仍然位于陶瓷外壳内。我将使用带有集成中断控制器的 powerPC (PPC) CPU,连接到 PCI 总线上的设备,作为应该可以很好使用的示例。
假设该设备是一个正在传输一些数据的串行端口。典型的串行端口驱动程序会将大量数据加载到设备的 FIFO 中,并且 CPU 可以在设备执行其操作时执行常规工作。通常,这些设备可以配置为在设备传输数据不足时生成中断请求,以便设备驱动程序可以返回并向其提供更多数据。
设备中的硬件逻辑将期望 PCI 总线中断确认,此时可能会发生一些事情。一些设备使用“自动向量”,这意味着它们依赖中断控制器来确保选择正确的服务例程。其他设备将有一个寄存器,设备驱动程序将对其进行预编程,其中包含一个中断向量,设备将将该中断向量放置在数据总线上以响应中断确认,以供中断控制器拾取。
PCI 总线只有四个中断请求线,因此我们的串行设备必须声明其中之一。 (目前哪个并不重要,它通常在某种程度上取决于插槽。)接下来是中断控制器(例如PIC / APIC),它将根据已设置的掩码位决定是否确认中断它自己的寄存器。假设它确认中断,则它要么从中断设备获取向量(通过数据总线线路),要么如果如此编程,则可以使用 APIC 自己的设备驱动程序提供的“固定”值。到目前为止,CPU 还没有意识到所有这些正在发生的事情,但这种情况即将改变。
现在是中断控制器引起 CPU 内核注意的时候了。 CPU 将有自己的中断屏蔽位,这可能会导致它忽略来自 PIC 的请求。假设 CPU 已准备好接受中断,那么现在就可以开始真正的操作了。当前指令通常必须在 ISR 开始之前退出,因此对于流水线处理器来说,这有点复杂,但足以说明在指令流中的某个点,处理器上下文被保存到堆栈和硬件中- 确定的ISR接管。
一些 CPU 内核具有多个请求线,并且可以通过硬件逻辑启动缩小 ISR 运行范围的过程,该硬件逻辑将 CPU 指令指针跳转到少数顶级处理程序之一。旧的 68K 以及可能其他的 68K 都是这样做的。 powerPC(我相信是x86)有一个中断请求输入。 x86 本身的行为有点像 PIC,并且可以从外部 PIC 获取向量,但 powerPC 只是跳转到固定地址 0x00000500。
在 PPC 中,0x0500 处的代码可能会立即跳到内存中的某个位置,那里有足够的空间用于一些重要的决策代码,但它仍然是中断服务例程。该例程将首先访问 PIC 并获取向量,并要求 PIC 停止向 CPU 内核发出中断请求。一旦知道了向量,顶层 ISR 就可以向更具体的处理程序发出请求,该处理程序将为所有已知正在使用该向量的设备提供服务。然后,向量特定的处理程序沿着分配给该向量的设备列表进行查找,检查这些设备中的中断状态位,以查看哪些设备需要服务。
当发现某个设备(如假设的串行端口)需要服务时,该设备的 ISR 会采取适当的操作,例如,将操作系统缓冲区中下一个 FIFO 的数据加载到端口的传输 FIFO 中。某些设备会自动丢弃中断请求以响应被访问,例如,将一个字节写入发送 FIFO 可能会导致串行端口设备取消断言请求线。其他设备将需要一个特殊的控制寄存器位来切换、设置、清除等等,以便丢弃请求。有无数种不同的 I/O 设备,而且似乎没有任何两种设备的工作方式是相同的,因此很难一概而论,但通常就是这样。
现在,显然还有更多要说的 - 中断优先级怎么样?多核处理器中会发生什么?嵌套中断控制器怎么样?但我已经在服务器上消耗了足够的空间。希望这些有帮助。
CPUs don't poll for interrupts, at least not in a software sense. With respect to software, interrupts are asynchronous events.
What happens is that hardware within the CPU recognizes the interrupt request, which is an electrical input on an interrupt line, and in response, sets aside the normal execution of events to respond to the interrupt. In most modern CPUs, what happens next is determined by a hardware handshake particular to the type of CPU, but most of them receive a number of some kind from the interrupting device. That number can be 8 bits or 32 or whatever, depending on the design of the CPU. The CPU then uses this interrupt number to index into the interrupt vector table, to find an address to begin execution of the interrupt service routine. Once that address is determined, (and the current execution context is safely saved to the stack) the CPU begins executing the ISR.
When two devices share an interrupt request line, they can cause different ISRs to run by returning a different interrupt number during that handshaking process. If you have enough vector numbers available, each interrupting device can use its own interrupt vector.
But two devices can even share an interrupt request line and an interrupt vector, provided that the shared ISR is clever enough to go back to all the possible sources of the given interrupt, and check status registers to see which device requested service.
A little more detail
Suppose you have a system composed of a CPU, and interrupt controller, and an interrupting device. In the old days, these would have been separate physical devices but now all three might even reside in the same chip, but all the signals are still there inside the ceramic case. I'm going to use a powerPC (PPC) CPU with an integrated interrupt controller, connected to a device on a PCI bus, as an example that should serve nicely.
Let's say the device is a serial port that's transmitting some data. A typical serial port driver will load bunch of data into the device's FIFO, and the CPU can do regular work while the device does its thing. Typically these devices can be configured to generate an interrupt request when the device is running low on data to transmit, so that the device driver can come back and feed more into it.
The hardware logic in the device will expect a PCI bus interrupt acknowledge, at which point, a couple of things can happen. Some devices use 'autovectoring', which means that they rely on the interrupt controller to see to it that the correct service routine gets selected. Others will have a register, which the device driver will pre-program, that contains an interrupt vector that the device will place on the data bus in response to the interrupt acknowledge, for the interrupt controller to pick up.
A PCI bus has only four interrupt request lines, so our serial device will have to assert one of those. (It doesn't matter which at the moment, it's usually somewhat slot dependent..) Next in line is the interrupt controller (e.g. PIC/APIC), that will decide whether to acknowledge the interrupt based on mask bits that have been set in its own registers. Assuming it acknowledges the interrupt, it either then obtains the vector from the interrupting device (via the data bus lines), or may if so programmed use a 'canned' value provided by the APIC's own device driver. So far, the CPU has been blissfully unaware of all these goings-on, but that's about to change.
Now it's time for the interrupt controller to get the attention of the CPU core. The CPU will have its own interrupt mask bit(s) that may cause it to just ignore the request from the PIC. Assuming that the CPU is ready to take interrupts, it's now time for the real action to start. The current instruction usually has to be retired before the ISR can begin, so with pipelined processors this is a little complicated, but suffice it to say that at some point in the instruction stream, the processor context is saved off to the stack and the hardware-determined ISR takes over.
Some CPU cores have multiple request lines, and can start the process of narrowing down which ISR runs via hardware logic that jumps the CPU instruction pointer to one of a handful of top level handlers. The old 68K, and possibly others did it that way. The powerPC (and I believe, the x86) have a single interrupt request input. The x86 itself behaves a bit like a PIC, and can obtain a vector from the external PIC(s), but the powerPC just jumps to a fixed address, 0x00000500.
In the PPC, the code at 0x0500 is probably just going to immediately jump out to somewhere in memory where there's room enough for some serious decision making code, but it's still the interrupt service routine. That routine will first go to the PIC and obtain the vector, and also ask the PIC to stop asserting the interrupt request into the CPU core. Once the vector is known, the top level ISR can case out to a more specific handler that will service all the devices known to be using that vector. The vector specific handler then walks down the list of devices assigned to that vector, checking interrupt status bits in those devices, to see which ones need service.
When a device, like the hypothetical serial port, is found wanting service, the ISR for that device takes appropriate actions, for example, loading the next FIFO's worth of data out of an operating system buffer into the port's transmit FIFO. Some devices will automatically drop their interrupt request in response to being accessed, for example, writing a byte into the transmit FIFO might cause the serial port device to de-assert the request line. Other devices will require a special control register bit to be toggled, set, cleared, what-have-you, in order to drop the request. There are zillions of different I/O devices and no two of them ever seem to do it the same way, so it's hard to generalize, but that's usually the way of it.
Now, obviously there's more to say - what about interrupt priorities? what happens in a multi-core processor? What about nested interrupt controllers? But I've burned enough space on the server. Hope any of this helps.
我在三年后才提出这个问题..希望我能提供帮助;)
Intel 8259A 或简称“PIC”有 8 个引脚,IRQ0-IRQ7,每个引脚连接到一个设备..
让我们假设你按下了一个按钮在键盘上..连接到KBD的IRQ1引脚的电压很高..所以在CPU中断后,确认中断bla bla bla ...PIC只是将8添加到了IRQ 线,因此 IRQ1 表示 1+8,表示 9,
因此 CPU 在向量表中的第 9 个条目上设置其 CS 和 IP。并且因为 IVT 是一个长整型数组,所以只需将单元数乘以 4 ;)
CPU .CS=IVT[9].CS
CPU.IP=IVT[9].IP
ESR 通过 I/O 端口处理设备;)
抱歉我的英语不好..不过我是阿拉伯人:)
I Came over this Question like after 3 years.. Hope I Can help ;)
The Intel 8259A or simply the "PIC" has 8 pins ,IRQ0-IRQ7, every pin connects to a single device..
Lets suppose that u pressed a button on the keyboard.. the voltage of the IRQ1 pin, which is connected to the KBD, is High.. so after the CPU gets interrupted, acknowledge the Interrupt bla bla bla... the PIC does simply add 8 to the number of the IRQ line so IRQ1 means 1+8 which means 9
SO the CPU sets its CS and IP on the 9th entry in the vector table.. and because the IVT is an array of longs it just multiply the number of cells by 4 ;)
CPU.CS=IVT[9].CS
CPU.IP=IVT[9].IP
the ESR deals with the device through the I/O ports ;)
Sorry for my bad english .. am an Arab though :)