MIPS interrupts and -icount
PATCH 1/1 MIPS interrupts and -icount
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
When hw interrupt pending bits in CP0_Cause are set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?
The following patch fixes the problem. Tested by booting the mips and mipsel images from http://wiki.qemu.org/Download. Also tested more with an experimental out-of-tree qemu machine I've got here running a linux-2.6.33 kernel.
I'd appreciate comments.
Thanks,
Edgar
commit c9af70e4587e1464b8019a059845492225733584
Author: Edgar E. Iglesias <[email protected]> Date: Thu Jul 22 13:14:52 2010 +0200
mips: Correct MIPS interrupt glue logic for icount
When hw interrupt pending bits in CP0_Cause are set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care.
This fixes MIPS external hw interrupts in combination with -icount.
hw/mips_int.c +6 -17
@@ -24,22 +24,6 @@#include "mips_cpudevs.h" #include "cpu.h" -/* Raise IRQ to CPU if necessary. It must be called every time the active -IRQ may change */ -void cpu_mips_update_irq (CPUState *env) -{ -if ((env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM )) { -if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - !(env->interrupt_request &CPU_INTERRUPT_HARD )) { -cpu_interrupt (env,CPU_INTERRUPT_HARD ); - } - }else -cpu_reset_interrupt (env,CPU_INTERRUPT_HARD ); -} -static void cpu_mips_irq_request (void *opaque,int irq,int level) {CPUState *env = (CPUState *)opaque;
@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) }else { env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } -cpu_mips_update_irq (env); + +if (env->CP0_Cause & CP0Ca_IP_mask) { +cpu_interrupt (env,CPU_INTERRUPT_HARD ); + }else { +cpu_reset_interrupt (env,CPU_INTERRUPT_HARD ); + } }void cpu_mips_irq_init_cpu (CPUState *env)
target-mips/cpu.h +0 -3
@@ -597,9 +597,6 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); -/* mips_int.c */ -void cpu_mips_update_irq (CPUState *env); -/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);
target-mips/op_helper.c +0 -11
@@ -1313,7 +1313,6 @@ void helper_mtc0_status (target_ulong arg1)default :cpu_abort (env,"Invalid MMU mode!\n" );break ; } } -cpu_mips_update_irq (env); }void helper_mttc0_status (target_ulong arg1)
@@ -1359,12 +1358,6 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } - -/* Handle the software interrupt as an hardware one, as they -are very similar */ -if (arg1 & CP0Ca_IP_mask) { -cpu_mips_update_irq (env); - } }void helper_mtc0_ebase (target_ulong arg1)
@@ -1793,8 +1786,6 @@ target_ulong helper_di (void)target_ulong t0 = env->CP0_Status; env->CP0_Status = t0 & ~(1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }
@@ -1803,8 +1794,6 @@ target_ulong helper_ei (void)target_ulong t0 = env->CP0_Status; env->CP0_Status = t0 | (1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?
I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Even in the i386 case, if none of the APIC accept interrupts, the glue logic doesn't transmit the interrupt to the CPU.
Quoted 7 lines
The following patch fixes the problem. Tested by booting the mips and mipsel images from http://wiki.qemu.org/Download. Also tested more with an experimental out-of-tree qemu machine I've got here running a linux-2.6.33 kernel.
I'd appreciate comments.
I don't think the patch is correct, all the places that are modified are places where interruptions can actually be triggered. What is probably wrong in the current code is that some instructions that can trigger exceptions are not between gen_io_start() / gen_io_end() blocks. There should be an I/O function in the QEMU sense, like when an interrupt is enabled on the i8259.
Quoted 30 lines
commit
c9af70e4587e1464b8019a059845492225733584Author: Edgar E. Iglesias <[email protected]> Date: Thu Jul 22 13:14:52 2010 +0200mips: Correct MIPS interrupt glue logic for icount
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care.This fixes MIPS external hw interrupts in combination with -icount.
Signed-off-by Edgar E. Iglesias <[email protected]>hw/mips_int.c +0
-6@@ -24,22 +24,6 @@#include "mips_cpudevs.h" #include "cpu.h" -/* Raise IRQ to CPU if necessary. It must be called every time the active -IRQ may change */ -void cpu_mips_update_irq (CPUState *env) -{ - if ((env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) &&
hw/mips_int.c line 42
Quoted 10 lines
hw/mips_int.c +0
-10- !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM)) { -if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - !(env->interrupt_request &CPU_INTERRUPT_HARD )) { -cpu_interrupt (env,CPU_INTERRUPT_HARD ); - } - } else -cpu_reset_interrupt (env ,CPU_INTERRUPT_HARD ); -} -
Removing these checks is fine as long as they are moved somewhere else. Otherwise interrupts are going to be triggered while they should not. Currently there is nothing that prevent that, and with your patch, the CPU will enter interrupt mode if an interrupt is triggered while already in interrupt mode.
Quoted 5 lines
hw/mips_int.c +0
-0static void cpu_mips_irq_request (void *opaque,int irq,int level) {CPUState *env = (CPUState *)opaque;@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) }else {
hw/mips_int.c static void cpu_mips_irq_request(void *opaque, int irq, int level) · line 45
Quoted 10 lines
hw/mips_int.c +6
-1env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } -cpu_mips_update_irq (env); + +if (env->CP0_Cause & CP0Ca_IP_mask) { +cpu_interrupt (env,CPU_INTERRUPT_HARD ); + }else { +cpu_reset_interrupt (env,CPU_INTERRUPT_HARD ); + } }
Probably here?
Quoted 20 lines
hw/mips_int.c +0
-0void cpu_mips_irq_init_cpu (CPUState *env)target-mips/cpu.h +0
-3@@ -597,9 +597,6 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); -/* mips_int.c */ -void cpu_mips_update_irq (CPUState *env); -/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);target-mips/op_helper.c +0
-0
target-mips/op_helper.c void helper_mtc0_status (target_ulong arg1) · line 1316
Quoted 5 lines
target-mips/op_helper.c +0
-1@@ -1313,7 +1313,6 @@ void helper_mtc0_status (target_ulong arg1)default :cpu_abort (env,"Invalid MMU mode!\n" );break ; } } -cpu_mips_update_irq (env); }
Removing that means that changing the interrupt enable register can't trigger exception anymore. This doesn't match real hardware anymore.
target-mips/op_helper.c void helper_mtc0_cause (target_ulong arg1) · line 1361
Quoted 12 lines
target-mips/op_helper.c +0
-6void helper_mttc0_status (target_ulong arg1)@@ -1359,12 +1358,6 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } - -/* Handle the software interrupt as an hardware one, as they -are very similar */ -if (arg1 & CP0Ca_IP_mask) { -cpu_mips_update_irq (env); - } }
Same here, it's not possible to trigger software interrupt anymore.
Quoted 11 lines
target-mips/op_helper.c +0
-2void helper_mtc0_ebase (target_ulong arg1)@@ -1793,8 +1786,6 @@ target_ulong helper_di (void)target_ulong t0 = env->CP0_Status; env->CP0_Status = t0 & ~(1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }
target-mips/op_helper.c target_ulong helper_ei (void) · line 1799
Quoted 8 lines
target-mips/op_helper.c +0
-2@@ -1803,8 +1794,6 @@ target_ulong helper_ei (void)target_ulong t0 = env->CP0_Status; env->CP0_Status = t0 | (1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }
Leaving form the interrupt should re-enable the interruptions, and thus also trigger one if one is pending.
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 9 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
Quoted 11 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?
Quoted 6 lines
I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See hw/mips_int.c and cpu-exec.c prior to the patch.
Quoted 55 lines
Even in the i386 case, if none of the APIC accept interrupts, the glue logic doesn't transmit the interrupt to the CPU.
Quoted 7 lines
The following patch fixes the problem. Tested by booting the mips and mipsel images from http://wiki.qemu.org/Download. Also tested more with an experimental out-of-tree qemu machine I've got here running a linux-2.6.33 kernel.
I'd appreciate comments.
I don't think the patch is correct, all the places that are modified are places where interruptions can actually be triggered. What is probably wrong in the current code is that some instructions that can trigger exceptions are not between
gen_io_start()/gen_io_end()blocks. There should be an I/O function in the QEMU sense, like when an interrupt is enabled on the i8259.Quoted 38 lines
commit
c9af70e4587e1464b8019a059845492225733584Author: Edgar E. Iglesias <[email protected]> Date: Thu Jul 22 13:14:52 2010 +0200mips: Correct MIPS interrupt glue logic for icount
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care.This fixes MIPS external hw interrupts in combination with -icount.
Signed-off-by Edgar E. Iglesias <[email protected]>hw/mips_int.c +0
-14@@ -24,22 +24,6 @@#include "mips_cpudevs.h" #include "cpu.h" -/* Raise IRQ to CPU if necessary. It must be called every time the active -IRQ may change */ -void cpu_mips_update_irq (CPUState *env) -{ -if ((env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM )) { -if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - !(env->interrupt_request &CPU_INTERRUPT_HARD )) { -cpu_interrupt (env,CPU_INTERRUPT_HARD ); - } - }else -cpu_reset_interrupt (env,CPU_INTERRUPT_HARD );
Quoted 8 lines
hw/mips_int.c line 42
Quoted 2 lines
hw/mips_int.c +0
-2-} -Removing these checks is fine as long as they are moved somewhere else. Otherwise interrupts are going to be triggered while they should not. Currently there is nothing that prevent that, and with your patch, the CPU will enter interrupt mode if an interrupt is triggered while already in interrupt mode.
The checks are already made in cpu-exec.c. On real hw, the PIC and external logic dont have access to the internal state of the CPU so they can't do any of those checks.
Quoted 39 lines
Quoted 6 lines
hw/mips_int.c +0
-0static void cpu_mips_irq_request (void *opaque,int irq,int level) {CPUState *env = (CPUState *)opaque;@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) }else {hw/mips_int.c static void cpu_mips_irq_request(void *opaque, int irq, int level) · line 45
Quoted 10 lines
hw/mips_int.c +6
-1env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } -cpu_mips_update_irq (env); + +if (env->CP0_Cause & CP0Ca_IP_mask) { +cpu_interrupt (env,CPU_INTERRUPT_HARD ); + }else { +cpu_reset_interrupt (env,CPU_INTERRUPT_HARD ); + } }Probably here?
Quoted 20 lines
hw/mips_int.c +0
-0void cpu_mips_irq_init_cpu (CPUState *env)target-mips/cpu.h +0
-3@@ -597,9 +597,6 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); -/* mips_int.c */ -void cpu_mips_update_irq (CPUState *env); -/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);target-mips/op_helper.c +0
-0@@ -1313,7 +1313,6 @@ void helper_mtc0_status (target_ulong arg1)
Quoted 8 lines
target-mips/op_helper.c void helper_mtc0_status (target_ulong arg1) · line 1316
Quoted 5 lines
target-mips/op_helper.c +0
-1default :cpu_abort (env,"Invalid MMU mode!\n" );break ; } } -cpu_mips_update_irq (env); }Removing that means that changing the interrupt enable register can't trigger exception anymore. This doesn't match real hardware anymore.
The external hw line is already active in this case, the interrupt should be taken as soon as the TB that unmasks the IE flag ends.
Quoted 15 lines
target-mips/op_helper.c void helper_mtc0_cause (target_ulong arg1) · line 1361
Quoted 13 lines
target-mips/op_helper.c +0
-6void helper_mttc0_status (target_ulong arg1)@@ -1359,12 +1358,6 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } - -/* Handle the software interrupt as an hardware one, as they -are very similar */ -if (arg1 & CP0Ca_IP_mask) { -cpu_mips_update_irq (env); - } }Same here, it's not possible to trigger software interrupt anymore.
Hmm, yes this part might cause problems. I'll check it out. Thanks.
Quoted 14 lines
Quoted 14 lines
target-mips/op_helper.c +0
-2void helper_mtc0_ebase (target_ulong arg1)@@ -1793,8 +1786,6 @@ target_ulong helper_di (void)target_ulong t0 = env->CP0_Status; env->CP0_Status = t0 & ~(1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }@@ -1803,8 +1794,6 @@ target_ulong helper_ei (void)target_ulong t0 = env->CP0_Status;
Quoted 9 lines
target-mips/op_helper.c target_ulong helper_ei (void) · line 1799
Quoted 6 lines
target-mips/op_helper.c +0
-2env->CP0_Status = t0 | (1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }Leaving form the interrupt should re-enable the interruptions, and thus also trigger one if one is pending.
I don't think so because the line should already be active, enabling the IE flag should cause the CPU to take the interrupt.
Thanks,
Edgar
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");
Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.
Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in cpu-exec.c or entirely modeled as a separate controller, that is in mips_int.c.
IMHO it should be in mips_int.c. It is an interrupt controller like another that combines a few interrupt lines into a single one that feeds the CPU. It is like for example the i8259, with the exception that the configuration is not done by load/store into MMIO area, but directly using CPU special registers. We should probably mark these instructions as I/O.
Quoted 65 lines
Quoted 55 lines
Even in the i386 case, if none of the APIC accept interrupts, the glue logic doesn't transmit the interrupt to the CPU.
Quoted 7 lines
The following patch fixes the problem. Tested by booting the mips and mipsel images from http://wiki.qemu.org/Download. Also tested more with an experimental out-of-tree qemu machine I've got here running a linux-2.6.33 kernel.
I'd appreciate comments.
I don't think the patch is correct, all the places that are modified are places where interruptions can actually be triggered. What is probably wrong in the current code is that some instructions that can trigger exceptions are not between
gen_io_start()/gen_io_end()blocks. There should be an I/O function in the QEMU sense, like when an interrupt is enabled on the i8259.Quoted 38 lines
commit
c9af70e4587e1464b8019a059845492225733584Author: Edgar E. Iglesias <[email protected]> Date: Thu Jul 22 13:14:52 2010 +0200mips: Correct MIPS interrupt glue logic for icount
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care.This fixes MIPS external hw interrupts in combination with -icount.
Signed-off-by Edgar E. Iglesias <[email protected]>hw/mips_int.c +0
-14@@ -24,22 +24,6 @@#include "mips_cpudevs.h" #include "cpu.h" -/* Raise IRQ to CPU if necessary. It must be called every time the active -IRQ may change */ -void cpu_mips_update_irq (CPUState *env) -{ -if ((env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM )) { -if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - !(env->interrupt_request &CPU_INTERRUPT_HARD )) { -cpu_interrupt (env,CPU_INTERRUPT_HARD ); - } - }else -cpu_reset_interrupt (env,CPU_INTERRUPT_HARD );Quoted 8 lines
hw/mips_int.c line 42
Quoted 2 lines
hw/mips_int.c +0
-2-} -Removing these checks is fine as long as they are moved somewhere else. Otherwise interrupts are going to be triggered while they should not. Currently there is nothing that prevent that, and with your patch, the CPU will enter interrupt mode if an interrupt is triggered while already in interrupt mode.
Quoted 3 lines
The checks are already made in
cpu-exec.c. On real hw, the PIC and external logic dont have access to the internal state of the CPU so they can't do any of those checks.
Ok, I haven't seen that. Indeed the checks should be on one side or another, but not on both.
Quoted 49 lines
Quoted 39 lines
Quoted 6 lines
hw/mips_int.c +0
-0static void cpu_mips_irq_request (void *opaque,int irq,int level) {CPUState *env = (CPUState *)opaque;@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) }else {hw/mips_int.c static void cpu_mips_irq_request(void *opaque, int irq, int level) · line 45
Quoted 10 lines
hw/mips_int.c +6
-1env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } -cpu_mips_update_irq (env); + +if (env->CP0_Cause & CP0Ca_IP_mask) { +cpu_interrupt (env,CPU_INTERRUPT_HARD ); + }else { +cpu_reset_interrupt (env,CPU_INTERRUPT_HARD ); + } }Probably here?
Quoted 20 lines
hw/mips_int.c +0
-0void cpu_mips_irq_init_cpu (CPUState *env)target-mips/cpu.h +0
-3@@ -597,9 +597,6 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); -/* mips_int.c */ -void cpu_mips_update_irq (CPUState *env); -/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);target-mips/op_helper.c +0
-0@@ -1313,7 +1313,6 @@ void helper_mtc0_status (target_ulong arg1)Quoted 8 lines
target-mips/op_helper.c void helper_mtc0_status (target_ulong arg1) · line 1316
Quoted 5 lines
target-mips/op_helper.c +0
-1default :cpu_abort (env,"Invalid MMU mode!\n" );break ; } } -cpu_mips_update_irq (env); }Removing that means that changing the interrupt enable register can't trigger exception anymore. This doesn't match real hardware anymore.
Quoted 1 line
The external hw line is already active in this case, the interrupt
It is not, as in your patch you are still masking CP0_Cause with CP0Ca_IP_mask.
If an interruption is not enabled in CP0Ca_IP_mask, it doesn't trigger the hw line. So when CP0Ca_IP_mask is changed, the interrupt is not triggered.
Quoted 44 lines
Quoted 16 lines
Quoted 4 lines
target-mips/op_helper.c +0
-0void helper_mttc0_status (target_ulong arg1)target-mips/op_helper.c void helper_mtc0_cause (target_ulong arg1) · line 1361
Quoted 10 lines
target-mips/op_helper.c +0
-6@@ -1359,12 +1358,6 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } - -/* Handle the software interrupt as an hardware one, as they -are very similar */ -if (arg1 & CP0Ca_IP_mask) { -cpu_mips_update_irq (env); - } }Same here, it's not possible to trigger software interrupt anymore.
Hmm, yes this part might cause problems. I'll check it out. Thanks.
Quoted 14 lines
Quoted 14 lines
target-mips/op_helper.c +0
-2void helper_mtc0_ebase (target_ulong arg1)@@ -1793,8 +1786,6 @@ target_ulong helper_di (void)target_ulong t0 = env->CP0_Status; env->CP0_Status = t0 & ~(1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }@@ -1803,8 +1794,6 @@ target_ulong helper_ei (void)target_ulong t0 = env->CP0_Status;Quoted 9 lines
target-mips/op_helper.c target_ulong helper_ei (void) · line 1799
Quoted 6 lines
target-mips/op_helper.c +0
-2env->CP0_Status = t0 | (1 << CP0St_IE); -cpu_mips_update_irq (env); -return t0; }Leaving form the interrupt should re-enable the interruptions, and thus also trigger one if one is pending.
Quoted 3 lines
I don't think so because the line should already be active, enabling the IE flag should cause the CPU to take the interrupt.
I haven't checked in details, but that's most probably true.
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 42 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.
Quoted 5 lines
Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.
If we choose having the interrupt controller as part of the CPU, which seems to be what you have chosen, the following patch should fix the remaining issues (and prepare the work for vector interrupt support):
hw/mips_int.c +9 -0
@@ -54,3 +54,12 @@ void cpu_mips_irq_init_cpu(CPUState *env) env->irq[i] = qi[i]; } } + +void cpu_mips_soft_irq (CPUState *env,int irq,int level) +{ +if (irq <0 || irq >2 ) { +return ; + } + +qemu_set_irq (env->irq[irq], level); +}
target-mips/cpu.h +3 -0
@@ -597,6 +597,9 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); +/* mips_int.c */ +void cpu_mips_soft_irq (CPUState *env,int irq,int level); +/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);
target-mips/helper.h +0 -1
@@ -2,7 +2,6 @@ DEF_HELPER_2(raise_exception_err, void, i32, int) DEF_HELPER_1(raise_exception, void, i32) -DEF_HELPER_0(interrupt_restart, void)#ifdef TARGET_MIPS64 DEF_HELPER_3 (ldl, tl, tl, tl, int)
target-mips/op_helper.c +8 -12
@@ -46,18 +46,6 @@ void helper_raise_exception (uint32_t exception)helper_raise_exception_err (exception,0 ); } -void helper_interrupt_restart (void ) -{ -if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM ) && - (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { - env->CP0_Cause &= ~(0x1f << CP0Ca_EC); -helper_raise_exception (EXCP_EXT_INTERRUPT ); - } -} -#if !defined(CONFIG_USER_ONLY )static void do_restore_state (void *pc_ptr) {
@@ -1346,6 +1334,7 @@ void helper_mtc0_cause (target_ulong arg1) {uint32_t mask =0x00C00300 ;uint32_t old = env->CP0_Cause; +int i;if (env->insn_flags &ISA_MIPS32R2 ) mask |=1 << CP0Ca_DC;
@@ -1358,6 +1347,13 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } + +/* Set/reset software interrupts */ +for (i =0 ; i <2 ; i++) { +if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { +cpu_mips_soft_irq (env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } }void helper_mtc0_ebase (target_ulong arg1)
target-mips/translate.c +10 -2
@@ -5190,7 +5190,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, intswitch (sel) {case 0 :save_cpu_state (ctx,1 ); +/* Mark as an IO operation because we may trigger a software +interrupt. */ +if (use_icount) { +gen_io_start (); + }gen_helper_mtc0_cause (arg); +if (use_icount) { +gen_io_end (); + } +/* Stop translation as we may have triggered an intetrupt */ + ctx->bstate =BS_STOP ; rn ="Cause" ;break ;default :
@@ -12365,7 +12375,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, }else {switch (ctx.bstate) {case BS_STOP : -gen_helper_interrupt_restart ();gen_goto_tb (&ctx,0 , ctx.pc);break ;case BS_NONE :
@@ -12373,7 +12382,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,gen_goto_tb (&ctx,0 , ctx.pc);break ;case BS_EXCP : -gen_helper_interrupt_restart ();tcg_gen_exit_tb (0 );break ;case BS_BRANCH :
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 47 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.
Quoted 6 lines
IMHO it should be in
mips_int.c. It is an interrupt controller like another that combines a few interrupt lines into a single one that feeds the CPU. It is like for example the i8259, with the exception that the configuration is not done by load/store into MMIO area, but directly using CPU special registers. We should probably mark these instructions as I/O.
Hi,
I agree that it's not obvious where things should be modeled, I'll try to explain my view.
As a first step I'm trying to model a MIPS configured with Vectored Interrupts. We've got external interrupt logic feeding the hw interrupt lines. These lines are level triggered, held active by the external logic as long as interrupts are pending. Regardless of wether the CPU want's to take the interrupt now or later. In fact, there is no way to access the internal flags from RTL logic located here (AFAIK). In my mind, this layers pretty much ends in hw/mips_int.c.
Internally in the MIPS core, I'm guessing there is logic that simpliy applies the internal CPU masks, outputing a single internal IRQ line that decides wether the CPU should take the IRQ or not. Here, things like IE flags etc matter. I don't have access to RTL on the MIPS side so I'm just guessing here.
In my mind, we should model this latter part by asserting INTERRUPT_HARD from hw/mips_int.c whenever any hw lines are active and letting the CPU in cpu-exec.c decide when to take the interrupt by applying it's internal masking.
Quoted 121 lines
Quoted 65 lines
Quoted 55 lines
Even in the i386 case, if none of the APIC accept interrupts, the glue logic doesn't transmit the interrupt to the CPU.
Quoted 7 lines
The following patch fixes the problem. Tested by booting the mips and mipsel images from http://wiki.qemu.org/Download. Also tested more with an experimental out-of-tree qemu machine I've got here running a linux-2.6.33 kernel.
I'd appreciate comments.
I don't think the patch is correct, all the places that are modified are places where interruptions can actually be triggered. What is probably wrong in the current code is that some instructions that can trigger exceptions are not between
gen_io_start()/gen_io_end()blocks. There should be an I/O function in the QEMU sense, like when an interrupt is enabled on the i8259.Quoted 38 lines
commit
c9af70e4587e1464b8019a059845492225733584Author: Edgar E. Iglesias <[email protected]> Date: Thu Jul 22 13:14:52 2010 +0200mips: Correct MIPS interrupt glue logic for icount
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care.This fixes MIPS external hw interrupts in combination with -icount.
Signed-off-by Edgar E. Iglesias <[email protected]>hw/mips_int.c +0
-14@@ -24,22 +24,6 @@#include "mips_cpudevs.h" #include "cpu.h" -/* Raise IRQ to CPU if necessary. It must be called every time the active -IRQ may change */ -void cpu_mips_update_irq (CPUState *env) -{ -if ((env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM )) { -if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - !(env->interrupt_request &CPU_INTERRUPT_HARD )) { -cpu_interrupt (env,CPU_INTERRUPT_HARD ); - } - }else -cpu_reset_interrupt (env,CPU_INTERRUPT_HARD );Quoted 8 lines
hw/mips_int.c line 42
Quoted 2 lines
hw/mips_int.c +0
-2-} -Removing these checks is fine as long as they are moved somewhere else. Otherwise interrupts are going to be triggered while they should not. Currently there is nothing that prevent that, and with your patch, the CPU will enter interrupt mode if an interrupt is triggered while already in interrupt mode.
Quoted 3 lines
The checks are already made in
cpu-exec.c. On real hw, the PIC and external logic dont have access to the internal state of the CPU so they can't do any of those checks.Ok, I haven't seen that. Indeed the checks should be on one side or another, but not on both.
Quoted 49 lines
Quoted 47 lines
Quoted 6 lines
hw/mips_int.c +0
-0static void cpu_mips_irq_request (void *opaque,int irq,int level) {CPUState *env = (CPUState *)opaque;@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) }else {hw/mips_int.c static void cpu_mips_irq_request(void *opaque, int irq, int level) · line 45
Quoted 10 lines
hw/mips_int.c +6
-1env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } -cpu_mips_update_irq (env); + +if (env->CP0_Cause & CP0Ca_IP_mask) { +cpu_interrupt (env,CPU_INTERRUPT_HARD ); + }else { +cpu_reset_interrupt (env,CPU_INTERRUPT_HARD ); + } }Probably here?
Quoted 20 lines
hw/mips_int.c +0
-0void cpu_mips_irq_init_cpu (CPUState *env)target-mips/cpu.h +0
-3@@ -597,9 +597,6 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); -/* mips_int.c */ -void cpu_mips_update_irq (CPUState *env); -/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);target-mips/op_helper.c +0
-0target-mips/op_helper.c void helper_mtc0_status (target_ulong arg1) · line 1316
Quoted 5 lines
target-mips/op_helper.c +0
-1@@ -1313,7 +1313,6 @@ void helper_mtc0_status (target_ulong arg1)default :cpu_abort (env,"Invalid MMU mode!\n" );break ; } } -cpu_mips_update_irq (env); }Removing that means that changing the interrupt enable register can't trigger exception anymore. This doesn't match real hardware anymore.
Quoted 8 lines
Quoted 1 line
The external hw line is already active in this case, the interrupt
It is not, as in your patch you are still masking
CP0_CausewithCP0Ca_IP_mask.If an interruption is not enabled in
CP0Ca_IP_mask, it doesn't trigger the hw line. So whenCP0Ca_IP_maskis changed, the interrupt is not triggered.
I think there is a bit of confusion here. CP0Ca_IP_mask never changes, it's a fix mask (like a helper define) that helps us extract the hw lines from the Cause register.
env->CP0_Cause & CP0Ca_IP_mask, simply means "are any hw irqs active?".
So, if hw interrupts are pending, INTERRUPT_HARD should be asserted and the CPU should be taking the interrupt as soon as the current TB ends and the internal flags (IE and others) satisfy the conditions.
Thanks,
Edgar
Quoted 49 lines · Aurelien Jarno
Quoted 42 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.Quoted 5 lines
Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.
Quoted 3 lines
If we choose having the interrupt controller as part of the CPU, which seems to be what you have chosen, the following patch should fix the remaining issues (and prepare the work for vector interrupt support):
Thanks,
That looks nice, specially the removing of the helper_interrupt_restart parts :)
I'll test it on my side and send you an ACK.
Thanks for your patience Aurelien,
Edgar
Quoted 132 lines
hw/mips_int.c +9
-0@@ -54,3 +54,12 @@ void cpu_mips_irq_init_cpu(CPUState *env) env->irq[i] = qi[i]; } } + +void cpu_mips_soft_irq (CPUState *env,int irq,int level) +{ +if (irq <0 || irq >2 ) { +return ; + } + +qemu_set_irq (env->irq[irq], level); +}target-mips/cpu.h +3
-0@@ -597,6 +597,9 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); +/* mips_int.c */ +void cpu_mips_soft_irq (CPUState *env,int irq,int level); +/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);target-mips/helper.h +0
-1@@ -2,7 +2,6 @@ DEF_HELPER_2(raise_exception_err, void, i32, int) DEF_HELPER_1(raise_exception, void, i32) -DEF_HELPER_0(interrupt_restart, void)#ifdef TARGET_MIPS64 DEF_HELPER_3 (ldl, tl, tl, tl, int)target-mips/op_helper.c +8
-12@@ -46,18 +46,6 @@ void helper_raise_exception (uint32_t exception)helper_raise_exception_err (exception,0 ); } -void helper_interrupt_restart (void ) -{ -if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM ) && - (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { - env->CP0_Cause &= ~(0x1f << CP0Ca_EC); -helper_raise_exception (EXCP_EXT_INTERRUPT ); - } -} -#if !defined(CONFIG_USER_ONLY )static void do_restore_state (void *pc_ptr) {@@ -1346,6 +1334,7 @@ void helper_mtc0_cause (target_ulong arg1) {uint32_t mask =0x00C00300 ;uint32_t old = env->CP0_Cause; +int i;if (env->insn_flags &ISA_MIPS32R2 ) mask |=1 << CP0Ca_DC;@@ -1358,6 +1347,13 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } + +/* Set/reset software interrupts */ +for (i =0 ; i <2 ; i++) { +if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { +cpu_mips_soft_irq (env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } }void helper_mtc0_ebase (target_ulong arg1)target-mips/translate.c +10
-2@@ -5190,7 +5190,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, intswitch (sel) {case 0 :save_cpu_state (ctx,1 ); +/* Mark as an IO operation because we may trigger a software +interrupt. */ +if (use_icount) { +gen_io_start (); + }gen_helper_mtc0_cause (arg); +if (use_icount) { +gen_io_end (); + } +/* Stop translation as we may have triggered an intetrupt */ + ctx->bstate =BS_STOP ; rn ="Cause" ;break ;default :@@ -12365,7 +12375,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, }else {switch (ctx.bstate) {case BS_STOP : -gen_helper_interrupt_restart ();gen_goto_tb (&ctx,0 , ctx.pc);break ;case BS_NONE :@@ -12373,7 +12382,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,gen_goto_tb (&ctx,0 , ctx.pc);break ;case BS_EXCP : -gen_helper_interrupt_restart ();tcg_gen_exit_tb (0 );break ;case BS_BRANCH :Signature · 3 lines
-- Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 54 lines · Edgar E. Iglesias
Quoted 49 lines · Aurelien Jarno
Quoted 42 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.Quoted 5 lines
Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.Quoted 3 lines
If we choose having the interrupt controller as part of the CPU, which seems to be what you have chosen, the following patch should fix the remaining issues (and prepare the work for vector interrupt support):
Quoted 6 lines
Thanks,
That looks nice, specially the removing of the
helper_interrupt_restartparts :)I'll test it on my side and send you an ACK.
I've tested this with the same images as before, they still work. I also created a synthetic testcase for the 2 software interrupt lines and they seem to behave OK. Our linux port was not so happy about seeing those raised though, so I had to hack a bit to see them in action :)
Would you mind applying your patch on top of mine?
Thanks alot,
Edgar
Quoted 137 lines
Thanks for your patience Aurelien,
EdgarQuoted 132 lines
hw/mips_int.c +9
-0@@ -54,3 +54,12 @@ void cpu_mips_irq_init_cpu(CPUState *env) env->irq[i] = qi[i]; } } + +void cpu_mips_soft_irq (CPUState *env,int irq,int level) +{ +if (irq <0 || irq >2 ) { +return ; + } + +qemu_set_irq (env->irq[irq], level); +}target-mips/cpu.h +3
-0@@ -597,6 +597,9 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value);void cpu_mips_start_count (CPUState *env);void cpu_mips_stop_count (CPUState *env); +/* mips_int.c */ +void cpu_mips_soft_irq (CPUState *env,int irq,int level); +/* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env,target_ulong address,int rw,int mmu_idx,int is_softmmu);target-mips/helper.h +0
-1@@ -2,7 +2,6 @@ DEF_HELPER_2(raise_exception_err, void, i32, int) DEF_HELPER_1(raise_exception, void, i32) -DEF_HELPER_0(interrupt_restart, void)#ifdef TARGET_MIPS64 DEF_HELPER_3 (ldl, tl, tl, tl, int)target-mips/op_helper.c +8
-12@@ -46,18 +46,6 @@ void helper_raise_exception (uint32_t exception)helper_raise_exception_err (exception,0 ); } -void helper_interrupt_restart (void ) -{ -if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM ) && - (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { - env->CP0_Cause &= ~(0x1f << CP0Ca_EC); -helper_raise_exception (EXCP_EXT_INTERRUPT ); - } -} -#if !defined(CONFIG_USER_ONLY )static void do_restore_state (void *pc_ptr) {@@ -1346,6 +1334,7 @@ void helper_mtc0_cause (target_ulong arg1) {uint32_t mask =0x00C00300 ;uint32_t old = env->CP0_Cause; +int i;if (env->insn_flags &ISA_MIPS32R2 ) mask |=1 << CP0Ca_DC;@@ -1358,6 +1347,13 @@ void helper_mtc0_cause (target_ulong arg1)else cpu_mips_start_count (env); } + +/* Set/reset software interrupts */ +for (i =0 ; i <2 ; i++) { +if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { +cpu_mips_soft_irq (env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } }void helper_mtc0_ebase (target_ulong arg1)target-mips/translate.c +10
-2@@ -5190,7 +5190,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, intswitch (sel) {case 0 :save_cpu_state (ctx,1 ); +/* Mark as an IO operation because we may trigger a software +interrupt. */ +if (use_icount) { +gen_io_start (); + }gen_helper_mtc0_cause (arg); +if (use_icount) { +gen_io_end (); + } +/* Stop translation as we may have triggered an intetrupt */ + ctx->bstate =BS_STOP ; rn ="Cause" ;break ;default :@@ -12365,7 +12375,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, }else {switch (ctx.bstate) {case BS_STOP : -gen_helper_interrupt_restart ();gen_goto_tb (&ctx,0 , ctx.pc);break ;case BS_NONE :@@ -12373,7 +12382,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,gen_goto_tb (&ctx,0 , ctx.pc);break ;case BS_EXCP : -gen_helper_interrupt_restart ();tcg_gen_exit_tb (0 );break ;case BS_BRANCH :Signature · 3 lines
-- Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 69 lines · Edgar E. Iglesias
Quoted 54 lines · Edgar E. Iglesias
Quoted 49 lines · Aurelien Jarno
Quoted 42 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.Quoted 5 lines
Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.Quoted 3 lines
If we choose having the interrupt controller as part of the CPU, which seems to be what you have chosen, the following patch should fix the remaining issues (and prepare the work for vector interrupt support):
Quoted 6 lines
Thanks,
That looks nice, specially the removing of the
helper_interrupt_restartparts :)I'll test it on my side and send you an ACK.
I've tested this with the same images as before, they still work. I also created a synthetic testcase for the 2 software interrupt lines and they seem to behave OK. Our linux port was not so happy about seeing those raised though, so I had to hack a bit to see them in action :)
Quoted 5 lines
Tested-by Edgar E. Iglesias <[email protected]>Would you mind applying your patch on top of mine?
Thanks for the tests, I have just applied it.
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 75 lines · Edgar E. Iglesias
Quoted 47 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.Quoted 6 lines
IMHO it should be in
mips_int.c. It is an interrupt controller like another that combines a few interrupt lines into a single one that feeds the CPU. It is like for example the i8259, with the exception that the configuration is not done by load/store into MMIO area, but directly using CPU special registers. We should probably mark these instructions as I/O.Hi,
I agree that it's not obvious where things should be modeled, I'll try to explain my view.
As a first step I'm trying to model a MIPS configured with Vectored Interrupts. We've got external interrupt logic feeding the hw interrupt lines. These lines are level triggered, held active by the external logic as long as interrupts are pending. Regardless of wether the CPU want's to take the interrupt now or later. In fact, there is no way to access the internal flags from RTL logic located here (AFAIK). In my mind, this layers pretty much ends in
hw/mips_int.c.Internally in the MIPS core, I'm guessing there is logic that simpliy applies the internal CPU masks, outputing a single internal IRQ line that decides wether the CPU should take the IRQ or not. Here, things like IE flags etc matter. I don't have access to RTL on the MIPS side so I'm just guessing here.
Quoted 5 lines
In my mind, we should model this latter part by asserting
INTERRUPT_HARDfromhw/mips_int.cwhenever any hw lines are active and letting the CPU incpu-exec.cdecide when to take the interrupt by applying it's internal masking.
Sorry to come back so long after this discussion, but I now have another argument. This commit causes a regression, the host CPU is now always at 100%. QEMU spent all its time looping because the CPU interrupt line is asserted.
Not asserting the CPU interrupt line when interrupts are disabled fixes the issue.
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Quoted 82 lines · Aurelien Jarno
Quoted 75 lines · Edgar E. Iglesias
Quoted 47 lines · Aurelien Jarno
Quoted 8 lines · Edgar E. Iglesias
Quoted 7 lines · Aurelien Jarno
Quoted 5 lines · Edgar E. Iglesias
Hi,
I'm seeing an error when emulating MIPS guests with -icount. In
cpu_interrupt:
cpu_abort(env, "Raised interrupt while not in I/O function");Quoted 7 lines
Quoted 2 lines
I am not able to reproduce the issue. Do you have more details how to reproduce the problem?
You need a machine with devices that raise the hw interrupts. I didn't see the error on the images on the wiki though. But I've got a machine here that trigs it easily. Will check if I can publish it and an image.
That would be nice if you can share it.
Quoted 14 lines
Quoted 14 lines
Quoted 2 lines
It seems to me like the MIPS interrupt glue logic between interrupt controllers and the MIPS core is not modeled correctly.
It seems indeed that sometimes interrupt are triggered while not in I/O functions, your patch addresses part of the problem.
Quoted 4 lines
When hw interrupt pending bits in
CP0_Causeare set, the CPU should see the hw interrupt line as active. The CPU may or may not take the interrupt based on internal state (global irq mask etc) but the glue logic shouldn't care about that. Am I missing something here?I don't think it is correct. On the real hardware, the interrupt line is actually active only when all conditions are fulfilled.
Quoted 8 lines
Quoted 3 lines
The thing to remember is that the interrupts are level triggered. So if an interrupt is masked, it should be rejected by the CPU, but could be triggered again as soon as the interrupt mask is changed.
Agreed, that behaviour is what I'm trying to acheive. The problem now is that the the level triggered line, prior to CPU masking is beeing masked by external logic. IMO it shouldnt. See
hw/mips_int.candcpu-exec.cprior to the patch.Actually all depends if you consider the MIPS interrupt controller part of the CPU or not. It could be entirely modeled in the CPU, that is in
cpu-exec.cor entirely modeled as a separate controller, that is inmips_int.c.Quoted 6 lines
IMHO it should be in
mips_int.c. It is an interrupt controller like another that combines a few interrupt lines into a single one that feeds the CPU. It is like for example the i8259, with the exception that the configuration is not done by load/store into MMIO area, but directly using CPU special registers. We should probably mark these instructions as I/O.Hi,
I agree that it's not obvious where things should be modeled, I'll try to explain my view.
As a first step I'm trying to model a MIPS configured with Vectored Interrupts. We've got external interrupt logic feeding the hw interrupt lines. These lines are level triggered, held active by the external logic as long as interrupts are pending. Regardless of wether the CPU want's to take the interrupt now or later. In fact, there is no way to access the internal flags from RTL logic located here (AFAIK). In my mind, this layers pretty much ends in
hw/mips_int.c.Internally in the MIPS core, I'm guessing there is logic that simpliy applies the internal CPU masks, outputing a single internal IRQ line that decides wether the CPU should take the IRQ or not. Here, things like IE flags etc matter. I don't have access to RTL on the MIPS side so I'm just guessing here.
Quoted 5 lines
In my mind, we should model this latter part by asserting
INTERRUPT_HARDfromhw/mips_int.cwhenever any hw lines are active and letting the CPU incpu-exec.cdecide when to take the interrupt by applying it's internal masking.
Quoted 7 lines
Sorry to come back so long after this discussion, but I now have another argument. This commit causes a regression, the host CPU is now always at 100%. QEMU spent all its time looping because the CPU interrupt line is asserted.
Not asserting the CPU interrupt line when interrupts are disabled fixes the issue.
Hi, I don't see this problem with the qemu.org test images and neither with my boards/images. I see QEMU basically not running at all when the guest is idle. Do you have more info on how to reproduce it?
If the CPU hw interrupt line is asserted it means some device is signaling interrupts. Maybe we are modling the wake up filter wrongly in target-mips/exec.h, maybe a real MIPS doesn't wakeup from sleep unless the irq passes the CPUs internal masking? The manuals are not really clear on this. I'm currently travelling and have no access to check with a real MIPS hw.
If your hw interrupt line is active all the time it sounds to me like if something is also wrong with either the guest software or a device model.
I think the following patch should restore the previous wait for interrupt wakeup behaviour to let the MIPS sleep until an irq passes the internal masking (but I'm not sure this is how real MIPS does it):
target-mips/exec.h +12 -3
@@ -19,10 +19,19 @@ register struct CPUMIPSState *env asm(AREG0);static inline int cpu_has_work (CPUState *env) { -return (env->interrupt_request & - (CPU_INTERRUPT_HARD |CPU_INTERRUPT_TIMER )); -} +int has_work =0 ; +/* MIPS wakes up when hw interrupts pass the internal masking? */ +if ((env->interrupt_request &CPU_INTERRUPT_HARD ) && +cpu_mips_hw_interrupts_pending (env)) { + has_work =1 ; + } +if (env->interrupt_request &CPU_INTERRUPT_TIMER ) { + has_work =1 ; + } + +return has_work; +}static inline int cpu_halted (CPUState *env) {
Hi,
Quoted 3 lines · Edgar E. Iglesias
Hi, I don't see this problem with the qemu.org test images and neither with my boards/images. I see QEMU basically not running at all when the guest is idle. Do you have more info on how to reproduce it?
I am seeing the problem with the MIPS malta board and the images from:
http://people.debian.org/~aurel32/qemu/mips/
Quoted 6 lines
If the CPU hw interrupt line is asserted it means some device is signaling interrupts. Maybe we are modling the wake up filter wrongly in
target-mips/exec.h, maybe a real MIPS doesn't wakeup from sleep unless the irq passes the CPUs internal masking? The manuals are not really clear on this. I'm currently travelling and have no access to check with a real MIPS hw.
According the manual I have checked, it is implementation dependent if the CPU exits from the WAIT instruction when a non-enabled interrupt is triggered. However for the few implementations I have checked (4k, 5k, 34k), the CPU only wakes-up if the interrupt can be taken.
Quoted 3 lines
If your hw interrupt line is active all the time it sounds to me like if something is also wrong with either the guest software or a device model.
The corresponding interrupt line is the timer one. It seems the kernel sometimes choose to ignore the timer instead of stopping it. I am only able to reproduce that with a dyntick enabled kernel.
Quoted 3 lines
I think the following patch should restore the previous wait for interrupt wakeup behaviour to let the MIPS sleep until an irq passes the internal masking (but I'm not sure this is how real MIPS does it):
It does, thanks a lot.
However, according to the manual I think we should also check if interrupts are enabled (if they are disabled, an interrupt can't be taken). I therefore propose the following patch:
Quoted 1 line
From
9c9e5f7ee1e897e408b1cd9f4c42ddf86c30aabeMon Sep 17 00:00:00 2001
From: Aurelien Jarno <[email protected]>
Date: Sat, 25 Dec 2010 22:56:32 +0100
Subject: [PATCH] target-mips: fix host CPU consumption when guest is idle
When the CPU is in wait state, do not wake-up if an interrupt can't be taken. This avoid host CPU running at 100% if a device (e.g. timer) has an interrupt line left enabled.
Also factorize code to check if interrupts are enabled in cpu_mips_hw_interrupts_pending().
Based on a patch from Edgar E. Iglesias <[email protected]>
--- cpu-exec.c | 6 +----- target-mips/cpu.h | 8 ++++++++ target-mips/exec.h | 18 +++++++++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-)
cpu-exec.c +1 -5
@@ -454,11 +454,7 @@ int cpu_exec(CPUState *env1) }#elif defined(TARGET_MIPS)if ((interrupt_request &CPU_INTERRUPT_HARD ) && -cpu_mips_hw_interrupts_pending (env) && - (env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags &MIPS_HFLAG_DM )) { +cpu_mips_hw_interrupts_pending (env)) {/* Raise it */ env->exception_index =EXCP_EXT_INTERRUPT ; env->error_code =0 ;
target-mips/cpu.h +8 -0
@@ -532,6 +532,14 @@ static inline int cpu_mips_hw_interrupts_pending(CPUState *env)int32_t status;int r; +if (!(env->CP0_Status & (1 << CP0St_IE)) || + (env->CP0_Status & (1 << CP0St_EXL)) || + (env->CP0_Status & (1 << CP0St_ERL)) || + (env->hflags &MIPS_HFLAG_DM )) { +/* Interrupts are disabled */ +return 0 ; + } + pending = env->CP0_Cause & CP0Ca_IP_mask; status = env->CP0_Status & CP0Ca_IP_mask;
target-mips/exec.h +15 -3
@@ -19,10 +19,22 @@ register struct CPUMIPSState *env asm(AREG0);static inline int cpu_has_work (CPUState *env) { -return (env->interrupt_request & - (CPU_INTERRUPT_HARD |CPU_INTERRUPT_TIMER )); -} +int has_work =0 ; + +/* It is implementation dependent if non-enabled interrupts +wake-up the CPU, however most of the implementations only +check for interrupts that can be taken. */ +if ((env->interrupt_request &CPU_INTERRUPT_HARD ) && +cpu_mips_hw_interrupts_pending (env)) { + has_work =1 ; + } +if (env->interrupt_request &CPU_INTERRUPT_TIMER ) { + has_work =1 ; + } + +return has_work; +}static inline int cpu_halted (CPUState *env) {
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net
Edgar E. Iglesias
Acked-byQuoted 46 lines · Aurelien Jarno
Hi,
Quoted 3 lines · Edgar E. Iglesias
Hi, I don't see this problem with the qemu.org test images and neither with my boards/images. I see QEMU basically not running at all when the guest is idle. Do you have more info on how to reproduce it?
I am seeing the problem with the MIPS malta board and the images from:
http://people.debian.org/~aurel32/qemu/mips/
Quoted 6 lines
If the CPU hw interrupt line is asserted it means some device is signaling interrupts. Maybe we are modling the wake up filter wrongly in
target-mips/exec.h, maybe a real MIPS doesn't wakeup from sleep unless the irq passes the CPUs internal masking? The manuals are not really clear on this. I'm currently travelling and have no access to check with a real MIPS hw.According the manual I have checked, it is implementation dependent if the CPU exits from the WAIT instruction when a non-enabled interrupt is triggered. However for the few implementations I have checked (4k, 5k, 34k), the CPU only wakes-up if the interrupt can be taken.
Quoted 3 lines
If your hw interrupt line is active all the time it sounds to me like if something is also wrong with either the guest software or a device model.
The corresponding interrupt line is the timer one. It seems the kernel sometimes choose to ignore the timer instead of stopping it. I am only able to reproduce that with a dyntick enabled kernel.
Quoted 3 lines
I think the following patch should restore the previous wait for interrupt wakeup behaviour to let the MIPS sleep until an irq passes the internal masking (but I'm not sure this is how real MIPS does it):
It does, thanks a lot.
However, according to the manual I think we should also check if interrupts are enabled (if they are disabled, an interrupt can't be taken). I therefore propose the following patch:
From
9c9e5f7ee1e897e408b1cd9f4c42ddf86c30aabeMon Sep 17 00:00:00 2001
From: Aurelien Jarno <[email protected]>
Date: Sat, 25 Dec 2010 22:56:32 +0100
Subject: [PATCH] target-mips: fix host CPU consumption when guest is idle
Quoted 6 lines
When the CPU is in wait state, do not wake-up if an interrupt can't be taken. This avoid host CPU running at 100% if a device (e.g. timer) has an interrupt line left enabled.
Also factorize code to check if interrupts are enabled in
cpu_mips_hw_interrupts_pending().
Thanks Aurelien,
It looks good, but one thing that worries me slightly is that streching the wakeup filter to include the IE related flags might break using the wait insn in polling mode.
for example:
di();init_hw();
while (1) {
wait_for_interrupt(); /* Power Save. */
do_work();
};I've seem similar constructions in bootcode/firmware for other archs. In this case I guess it would be using undefined behaviour on the mips though, so I'm OK with either patch.
At some point I'll see if I can check the IE flags behaviour with a real 34k and we can finetune the models with follow-up patches if needed.
Cheers
Quoted 64 lines · Edgar E. Iglesias
Quoted 46 lines · Aurelien Jarno
Hi,
Quoted 3 lines · Edgar E. Iglesias
Hi, I don't see this problem with the qemu.org test images and neither with my boards/images. I see QEMU basically not running at all when the guest is idle. Do you have more info on how to reproduce it?
I am seeing the problem with the MIPS malta board and the images from:
http://people.debian.org/~aurel32/qemu/mips/
Quoted 6 lines
If the CPU hw interrupt line is asserted it means some device is signaling interrupts. Maybe we are modling the wake up filter wrongly in
target-mips/exec.h, maybe a real MIPS doesn't wakeup from sleep unless the irq passes the CPUs internal masking? The manuals are not really clear on this. I'm currently travelling and have no access to check with a real MIPS hw.According the manual I have checked, it is implementation dependent if the CPU exits from the WAIT instruction when a non-enabled interrupt is triggered. However for the few implementations I have checked (4k, 5k, 34k), the CPU only wakes-up if the interrupt can be taken.
Quoted 3 lines
If your hw interrupt line is active all the time it sounds to me like if something is also wrong with either the guest software or a device model.
The corresponding interrupt line is the timer one. It seems the kernel sometimes choose to ignore the timer instead of stopping it. I am only able to reproduce that with a dyntick enabled kernel.
Quoted 3 lines
I think the following patch should restore the previous wait for interrupt wakeup behaviour to let the MIPS sleep until an irq passes the internal masking (but I'm not sure this is how real MIPS does it):
It does, thanks a lot.
However, according to the manual I think we should also check if interrupts are enabled (if they are disabled, an interrupt can't be taken). I therefore propose the following patch:
From
9c9e5f7ee1e897e408b1cd9f4c42ddf86c30aabeMon Sep 17 00:00:00 2001
From: Aurelien Jarno <[email protected]>
Date: Sat, 25 Dec 2010 22:56:32 +0100
Subject: [PATCH] target-mips: fix host CPU consumption when guest is idleQuoted 6 lines
When the CPU is in wait state, do not wake-up if an interrupt can't be taken. This avoid host CPU running at 100% if a device (e.g. timer) has an interrupt line left enabled.
Also factorize code to check if interrupts are enabled in
cpu_mips_hw_interrupts_pending().Thanks Aurelien,
It looks good, but one thing that worries me slightly is that streching the wakeup filter to include the IE related flags might break using the wait insn in polling mode.
for example:
di();init_hw();
Quoted 8 lines
while (1) { wait_for_interrupt(); /* Power Save. */ do_work(); };I've seem similar constructions in bootcode/firmware for other archs. In this case I guess it would be using undefined behaviour on the mips though, so I'm OK with either patch.
Yes, the manuals are not fully clear, however it seems to be a possible behaviour for some implementations, also it was the behaviour prior to your patch. Note also that in the case above, the CPU can still be woken-up by an NMI, though it doesn't seem to be implemented in QEMU yet.
Quoted 2 lines
At some point I'll see if I can check the IE flags behaviour with a real 34k and we can finetune the models with follow-up patches if needed.
Ok, that would be nice if you can do it.
Quoted 2 lines
Thanks for your review.
Cheers,
Aurélien
Signature · 2 lines
Aurelien Jarno GPG: 1024D/F1BCDB73 [email protected] http://www.aurel32.net