[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: exact ISR triggering
Re: exact ISR triggering
Mon, 24 Feb 2020 10:59:31 +0000
On Sun, 23 Feb 2020 at 23:08, lesto fante <address@hidden> wrote:
> I am a baremetal programmer for the ARM architecture and I have a
> library of method to synchronize data between main() and ISR, and i
> would like to have a way to test them in a comprehensive way.
> The idea is to write a minimal code in the main(), and then for each
> atomic operation in the main trigger the isr, then check that the
> state of the system is as expected (basically a unit test).
> Is there a way to trigger those ISR exactly when I want, and to have a
> callback every time an atomic operation is completed, and to know if
> that operation was in the ISR?
(This reply is a lot of "no not really", but there is a suggestion
or two you might try at the end.)
If I understand you correctly, in general, no you can't. IRQ
and FIQ interrupts aren't guaranteed to be exactly timed, and
QEMU doesn't give cycle-accurate results, so even if you set
up a timer device to fire at about the right time the interrupt
might arrive earlier or later. (In particular, if you don't pass
QEMU the -singlestep argument then you'll only ever see
interrupts at the end of a translation block (ie typically after
a guest branch instruction). If you're prepared to write a special
purpose "deliver me an interrupt after N 'cycles'" timer device,
and run QEMU with -single-step and with a -icount option that's
calculated to match up with the frequency of that timer device
as programmed into QEMU's source code, you can get vaguely
close, but you still would need your guest test code to cope
with the interrupt arriving only vaguely at the right time (eg
by having sequences of 'nop' instructions to widen the window
when it's ok for the interrupt to arrive, plus fallback code to
do something sensible if it arrived too late).
More generally, QEMU isn't necessarily a great place to try
to test the viability of atomic operation implementations:
* in normal (without -singlestep) operation we won't take
interrupts until the end of a block, so many races will
* we don't emulate the exact memory model of a
guest CPU: for instance the Arm memory model is
quite weak and requires memory barriers in certain
places, but since QEMU implements the memory accesses
as host accesses it will often still work correctly without
the barriers when real hardware would break
So it can be a useful CI/smoke test "this isn't totally
broken" but it's not a replacement for also testing
on real hardware at some point.
An approach that might work for you, and at least be
better than simply calling the ISR as a C function,
would be to block interrupts (using the CPSR.I bit),
and then trigger an interrupt, which won't be taken as
it is blocked. Then instead of your main() function
calling the ISR function, it can just do a single insn
"unblock IRQ", which should cause the ISR to be
taken more-or-less immediately (you might want to
throw some nops after the enable to be safe). The
ISR routine can do whatever it needs to do, and then
re-trigger the ISR (IRQ should be blocked in the ISR handler)
set SPSR so IRQ will remain blocked on return from
interrupt, and return from the interrupt; main() execution
would then resume with the next test case.
If you just want "do a random test of whether
an IRQ arriving at the wrong time does bad things"
then you could just have a loop where you
program a timer interrupt to fire midway through
your test case, and then use a loop to do this a
lot of times with varying timer-timeout values, and
run that with suitable -singlestep and -icount options.
You'd probably want some calibration code so the
testing code automatically makes the timeout longer
if it fires before the test case even starts and
shorter if it fires after the test case has finished.
That wouldn't be guaranteed to be comprehensive
coverage but if you loop round enough times it would
have a good chance of catching that sort of bug I think.