* [Qemu-devel] Questions about the flow of interrupt simulation @ 2018-05-23 10:45 Eva Chen 2018-05-24 13:40 ` Peter Maydell 0 siblings, 1 reply; 4+ messages in thread From: Eva Chen @ 2018-05-23 10:45 UTC (permalink / raw) To: qemu-devel Hi, I have added a new virtual device under qemu/hw, and a device driver in the source code of guest OS (I use arm linux). Since I want to add an interrupt to the virtual device, I am tracing the flow of interrupt simulation of QEMU. However, I have some questions about the flow of interrupt, and wondering if I could ask here for some help. I use $qemu-system-aarch64 -machine virt. Take the flow of interrupt that generated from the UART pl011 device as example. First an interrupt, CPU_INTERRUPT_HARD, will be sent from device to GIC for telling CPU that this device finished some job, then this interrupt wiil be transformed into EXCP_IRQ in aarch64_cpu_do_interrupt() and interrupt handled by CPU. - Details of function call: 1. Device to GIC : pl011_write() => pl011_update() => gic_set_irq() 2. CPU handling : cpu_exec() => arm_cpu_exec_interrupt() => aarch64_cpu_do_interrupt() Guest CPU's pc (env->pc) will be changed to the address of interrupt service routine in aarch64_cpu_do_interrupt(). The question is: Will CPU execute the ISR that env->pc assigned? If yes, is the ISR defined in the guest OS (I use arm-linux kernel image)? How can I see the code that handling the EXCP_IRQ? Is there any method I can set some breakpoint in gdb or set some log flags to see the handler? If not, then is that all guest ISR will not be called by using QEMU? The reason that I have this question is that I look into the cpu_exec(), find that tb_find() will be executed after handling an interrupt. At this time, the ISR address in env->pc should be replaced by the TB that is going to be executed. However, I don't know how to check my thought since I can't debug of execution in the TB so I ask for some help here. I will be grateful for any advice, thanks. Sincerely, Eva ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] Questions about the flow of interrupt simulation 2018-05-23 10:45 [Qemu-devel] Questions about the flow of interrupt simulation Eva Chen @ 2018-05-24 13:40 ` Peter Maydell 2018-06-01 6:17 ` Eva Chen 0 siblings, 1 reply; 4+ messages in thread From: Peter Maydell @ 2018-05-24 13:40 UTC (permalink / raw) To: Eva Chen; +Cc: QEMU Developers On 23 May 2018 at 11:45, Eva Chen <debby83729@gmail.com> wrote: > Hi, > > I have added a new virtual device under qemu/hw, and a device driver in the > source code of guest OS (I use arm linux). > Since I want to add an interrupt to the virtual device, I am tracing the > flow of interrupt simulation of QEMU. > However, I have some questions about the flow of interrupt, and wondering > if I could ask here for some help. > > I use $qemu-system-aarch64 -machine virt. > Take the flow of interrupt that generated from the UART pl011 device as > example. > First an interrupt, CPU_INTERRUPT_HARD, will be sent from device to GIC for > telling CPU that this device finished some job, then this interrupt wiil be > transformed into EXCP_IRQ in aarch64_cpu_do_interrupt() and interrupt > handled by CPU. This isn't quite the way it works. What happens is more like: * pl011 device calls qemu_set_irq() on its outbound IRQ line * the board model has connected that line up to one of the GIC's input lines * the GIC function on the other end of the qemu_irq is called and does the necessary processing of the input line state change. (For the gicv2 this is the gic_set_irq() function.) * if the GIC state is such that it should now signal an IRQ to the CPU it will do that. (This is not necessarily going to happen: for instance the interrupt might be disabled in the GIC, or another higher priority interrupt might already be being signaled.) The GIC does this by calling qemu_set_irq() on its outbound IRQ or FIQ line. * the CPU object on the other end of that IRQ or FIQ line will have its arm_cpu_set_irq() function called. All this function does is make a note so that we stop executing code and start doing something else; we do that by calling cpu_interrupt(). We use CPU_INTERRUPT_HARD/FIQ/VIRQ/VFIQ here to distinguish which of our 4 interrupt lines this is; nothing outside the CPU cares about those names. * cpu_interrupt() itself doesn't do anything, it just sets a flag which the thread executing guest cpu code will check. * in the guest-cpu-execution code path you have traced the relevant flow here: > 2. CPU handling : cpu_exec() => arm_cpu_exec_interrupt() => > aarch64_cpu_do_interrupt() > Guest CPU's pc (env->pc) will be changed to the address of interrupt > service routine in aarch64_cpu_do_interrupt(). Some notes: (1) I've assumed GICv2 in the above; the GICv3 is a bit more complex but the basic idea is similar (2) The GIC is a device model that is not "special" just because it happens to be an interrupt controller. It's just a model of a bit of hardware that has some input lines and some output lines, and sets the output lines as needed depending on what the input lines do. It happens that for an interrupt controller the input lines are interrupt lines from devices and the outputs are IRQ and FIQ to the CPU. (3) qemu_irq is a generic facility that roughly models a signal or 'wire' between two QEMU devices. On the sending side, you call qemu_set_irq() to set the level. On the receiving side, a function which you registered is called whenever the level changes. In the board model code, you have to connect the two ends together. > The question is: > Will CPU execute the ISR that env->pc assigned? Yes. The emulated CPU here behaves exactly like hardware. When an interrupt is taken, the PC is set to the exception vector for it. (The exact address depends on whether the exception is a synchronous exception, SError, IRQ or FIQ; which exception level we are taking the exception to; and the value in the VBAR register.) It is up to the guest to have put some useful code at that address. If it has not, then we will start executing whatever garbage was at that address. (if that garbage is all-zeroes, then we'll take an immediate exception because that's not a valid A64 instruction, and likely go into an infinite loop of taking exceptions. This is the same as what the hardware does in that situation.) If your guest OS is Linux then it will have installed handlers for these exceptions. > The reason that I have this question is that I look into the cpu_exec(), > find that tb_find() will be executed after handling an interrupt. At this > time, the ISR address in env->pc should be replaced by the TB that is going > to be executed. However, I don't know how to check my thought since I can't > debug of execution in the TB so I ask for some help here. This is correct, but you shouldn't usually need to look into QEMU's internals at this low a level. You can debug either using QEMU's gdb debugstub, or by using the -d options to enable tracing of events like execution, interrupts and so on. thanks -- PMM ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] Questions about the flow of interrupt simulation 2018-05-24 13:40 ` Peter Maydell @ 2018-06-01 6:17 ` Eva Chen 2018-06-01 9:25 ` Peter Maydell 0 siblings, 1 reply; 4+ messages in thread From: Eva Chen @ 2018-06-01 6:17 UTC (permalink / raw) To: QEMU Developers Thanks deeply for your clear explanation! Let me try to conclude what I learned from your description. qemu_set_irq() qemu_set_irq() [ device ] -----------------> [ GIC ] ---------------------> [ CPU ] Detailed: [device] =>qemu_set_irq() [GIC] =>gic_set_irq() =>gic_update() =>qemu_set_irq() [CPU] => arm_cpu_set_irq() GIC decides to send an irq to CPU or not depends on the level that device sends or others reason like interrupt mask. GIC turns the interrupt into an interrupt type: ARM_CPU_HARD/FIQ/VIRQ/VFIQ. In arm_cpu_set_irq(), it turns ARM_CPU_HARD/FIQ/VIRQ/VFIQ into CPU_INTERRUPT_HARD/FIQ/VIRQ/VFIQ. cpu_interrupt() sets cpu->interrupt_request. Then I have some following questions: 1. There are two kinds of interrupt: edge triggered and level triggered. I have seen two code segment related to the level: gic_set_irq() and arm_cpu_set_irq(). In gic_set_irq(), if level == GIC_TEST_LEVEL(irq, cm), which means the level is not changed, will return. In arm_cpu_set_irq() said that if level ==1, call cpu_interrupt(). if level==0, call cpu_reset_interrupt(), which will clean up that irq bits.. Does that mean all interrupt in arm are level triggered(high level)? How to know the triggered type of interrupt? 2. interrupt signal will be passed through GIC from device to CPU. There are four types of interrupt in CPU: CPU_INTERRUPT_HARD/FIQ/VIRQ/VFIQ. Where exactly define the CPU_INTERRUPT_{type} that device's interrupt corresponded? 3. I have seen others device's code under qemu/hw directory. Almost all device will call qemu_set_irq() at the end of device's read/write. Is that for the purpose of a device to tell CPU that it has done some works? but the second parameter of qemu_set_irq(), level, will be set to a different value(not always 1 or 0), which sometimes will cause the interrupt return at gic_set_irq() instead of passing to CPU. What does the interrupt at the end of device_read/write(device_update()) mean? I think I might ask some basic questions of interrupt. If there is any documents or tutorial about interrupt, please share with me, I am willing to study it. Sincerely, Eva 2018-05-24 21:40 GMT+08:00 Peter Maydell <peter.maydell@linaro.org>: > On 23 May 2018 at 11:45, Eva Chen <debby83729@gmail.com> wrote: > > Hi, > > > > I have added a new virtual device under qemu/hw, and a device driver in > the > > source code of guest OS (I use arm linux). > > Since I want to add an interrupt to the virtual device, I am tracing the > > flow of interrupt simulation of QEMU. > > However, I have some questions about the flow of interrupt, and wondering > > if I could ask here for some help. > > > > I use $qemu-system-aarch64 -machine virt. > > Take the flow of interrupt that generated from the UART pl011 device as > > example. > > First an interrupt, CPU_INTERRUPT_HARD, will be sent from device to GIC > for > > telling CPU that this device finished some job, then this interrupt wiil > be > > transformed into EXCP_IRQ in aarch64_cpu_do_interrupt() and interrupt > > handled by CPU. > > This isn't quite the way it works. > > What happens is more like: > * pl011 device calls qemu_set_irq() on its outbound IRQ line > * the board model has connected that line up to one of the GIC's > input lines > * the GIC function on the other end of the qemu_irq is called > and does the necessary processing of the input line state change. > (For the gicv2 this is the gic_set_irq() function.) > * if the GIC state is such that it should now signal an IRQ to > the CPU it will do that. (This is not necessarily going to happen: > for instance the interrupt might be disabled in the GIC, or > another higher priority interrupt might already be being signaled.) > The GIC does this by calling qemu_set_irq() on its outbound > IRQ or FIQ line. > * the CPU object on the other end of that IRQ or FIQ line will have > its arm_cpu_set_irq() function called. All this function does is > make a note so that we stop executing code and start doing > something else; we do that by calling cpu_interrupt(). We use > CPU_INTERRUPT_HARD/FIQ/VIRQ/VFIQ here to distinguish which of our > 4 interrupt lines this is; nothing outside the CPU cares about > those names. > * cpu_interrupt() itself doesn't do anything, it just sets a flag > which the thread executing guest cpu code will check. > * in the guest-cpu-execution code path you have traced the relevant > flow here: > > 2. CPU handling : cpu_exec() => arm_cpu_exec_interrupt() => > > aarch64_cpu_do_interrupt() > > Guest CPU's pc (env->pc) will be changed to the address of interrupt > > service routine in aarch64_cpu_do_interrupt(). > > Some notes: > (1) I've assumed GICv2 in the above; the GICv3 is a bit more complex > but the basic idea is similar > (2) The GIC is a device model that is not "special" just because > it happens to be an interrupt controller. It's just a model of a > bit of hardware that has some input lines and some output lines, > and sets the output lines as needed depending on what the input lines do. > It happens that for an interrupt controller the input lines are > interrupt lines from devices and the outputs are IRQ and FIQ to the CPU. > (3) qemu_irq is a generic facility that roughly models a signal or > 'wire' between two QEMU devices. On the sending side, you call > qemu_set_irq() to set the level. On the receiving side, a function > which you registered is called whenever the level changes. In the > board model code, you have to connect the two ends together. > > > The question is: > > Will CPU execute the ISR that env->pc assigned? > > Yes. The emulated CPU here behaves exactly like hardware. When > an interrupt is taken, the PC is set to the exception vector for > it. (The exact address depends on whether the exception is a > synchronous exception, SError, IRQ or FIQ; which exception level > we are taking the exception to; and the value in the VBAR register.) > > It is up to the guest to have put some useful code at that address. > If it has not, then we will start executing whatever garbage was > at that address. (if that garbage is all-zeroes, then we'll take > an immediate exception because that's not a valid A64 instruction, > and likely go into an infinite loop of taking exceptions. This is > the same as what the hardware does in that situation.) > > If your guest OS is Linux then it will have installed handlers > for these exceptions. > > > The reason that I have this question is that I look into the cpu_exec(), > > find that tb_find() will be executed after handling an interrupt. At this > > time, the ISR address in env->pc should be replaced by the TB that is > going > > to be executed. However, I don't know how to check my thought since I > can't > > debug of execution in the TB so I ask for some help here. > > This is correct, but you shouldn't usually need to look into QEMU's > internals at this low a level. You can debug either using QEMU's > gdb debugstub, or by using the -d options to enable tracing of > events like execution, interrupts and so on. > > thanks > -- PMM > ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] Questions about the flow of interrupt simulation 2018-06-01 6:17 ` Eva Chen @ 2018-06-01 9:25 ` Peter Maydell 0 siblings, 0 replies; 4+ messages in thread From: Peter Maydell @ 2018-06-01 9:25 UTC (permalink / raw) To: Eva Chen; +Cc: QEMU Developers On 1 June 2018 at 07:17, Eva Chen <debby83729@gmail.com> wrote: > 1. There are two kinds of interrupt: edge triggered and level triggered. > I have seen two code segment related to the level: gic_set_irq() and > arm_cpu_set_irq(). > In gic_set_irq(), if level == GIC_TEST_LEVEL(irq, cm), which means the > level is not changed, will return. > In arm_cpu_set_irq() said that if level ==1, call cpu_interrupt(). if > level==0, call cpu_reset_interrupt(), which will clean up that irq bits.. > Does that mean all interrupt in arm are level triggered(high level)? > How to know the triggered type of interrupt? This is mixing up interrupts in two different places. For the Arm architecture, IRQ and FIQ are always level-sensitive: the thing which sets them (the GIC, typically) has to set them and keep them set until the CPU acknowledges them. For the GIC, its input interrupts may be either level sensitive or edge sensitive. This is configurable for each interrupt on GICv2 by writing to the GICD_ICFGRn registers. The gic_set_irq() code implements the behaviour that the GIC specification requires, depending on whether the ICFGRn register says that interrupt should be edge or level triggered. Other interrupt controllers that QEMU models may behave differently. (For instance the ARMv7M NVIC is different again.) > 2. interrupt signal will be passed through GIC from device to CPU. There > are four types of interrupt in CPU: CPU_INTERRUPT_HARD/FIQ/VIRQ/VFIQ. > Where exactly define the CPU_INTERRUPT_{type} that device's interrupt > corresponded? Again, this is configurable by the guest by writing to GIC registers. In the GICv2, the GICD_IGROUPRn registers set the whether the interrupt should be in "group 0" or "group 1". Group 1 interrupts always cause an IRQ; group 0 interrupts cause either IRQ or FIQ depending on the setting of the GICC_CTLR FIQEn bit. (The expected use is that interrupts configured for use with the TrustZone Secure World will use FIQ and those configured for use with the NonSecure World will use IRQ.) VIRQ and VFIQ are for when the GIC and CPU support the Virtualization Extension. The behaviour of all of this is defined by the GIC specification; QEMU just has to implement what the hardware does. > 3. I have seen others device's code under qemu/hw directory. Almost all > device will call qemu_set_irq() at the end of device's read/write. Is that > for the purpose of a device to tell CPU that it has done some works? > but the second parameter of qemu_set_irq(), level, will be set to a > different value(not always 1 or 0), which sometimes will cause the > interrupt return at gic_set_irq() instead of passing to CPU. > What does the interrupt at the end of device_read/write(device_update()) > mean? The best way to think of this is not to try to think about whether the interrupt line is connected to the CPU or anything else. Just think about a device model as being an emulation of a particular bit of hardware. For instance, take the pl011 UART. The specification for that UART says that when certain conditions inside the device are true, the UART will assert its outgoing interrupt line. So our model also must check those conditions and call qemu_set_irq() to raise and lower the interrupt at the right time. The common way to code this is to have a function which is called whenever any of the relevant state has changed, which rechecks the conditions and calls qemu_set_irq(). The "purpose" of this code is just to behave the way the hardware behaves. Commonly, the output IRQ line from a device is connected to an interrupt controller and thus to a CPU, but it doesn't have to be. On some boards, the IRQ line might not be connected to anything. Or it might be connected up to some other device which provides its value to the guest via a status register. Or perhaps it's ORed together with lines from other devices and the output of the OR gate goes to the interrupt controller. If you're designing a board in real hardware, you are taking various components (UART, interrupt controller, etc) and connecting them up to implement a useful design. In QEMU, we also take various components and connect them up, to produce the same design the hardware has. qemu_set_irq() is usually just modelling what in the hardware is a simple wire. The source end calls this function to say "the wire is at logical 0/1", and on the destination end a function is called to handle that. It is also possible to pass in a value other than 0 or 1. This happens in two cases: (1) a bug, where the source end really ought to be using 0 or 1; often this doesn't have any visible bad effects because the destination end is testing 0 vs not-0, rather than 0 vs 1 (2) we really do want to transfer an integer rather than just a 0-vs-1 level. This is less common and only happens when both ends of the "wire" know that that's the convention they want to use. I think the overall theme of my reply is that fundamentally QEMU is modelling hardware. If you want to understand why parts of QEMU are connected the way they are, or why they behave in a particular way, then looking at what the specification of the hardware is and how the hardware is connected, will often help a lot. thanks -- PMM ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-06-01 9:25 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-05-23 10:45 [Qemu-devel] Questions about the flow of interrupt simulation Eva Chen 2018-05-24 13:40 ` Peter Maydell 2018-06-01 6:17 ` Eva Chen 2018-06-01 9:25 ` Peter Maydell
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.