[raspi-internals] VC4 processor modes and returning from exceptions

  • From: Julian Brown <julianbrown99@xxxxxxxxx>
  • To: raspi-internals@xxxxxxxxxxxxx, Herman Hermitage <hermanhermitage@xxxxxxxxxxx>
  • Date: Wed, 19 Oct 2016 20:48:15 +0100

Hi,

I've hit a snag trying to set up hardware testing (on an r-pi model
1b). The basic set up is that a customised (i.e. hacked) version of
Kristina's firmware code is used to start up the VC4 and the SDRAM,
then relocate itself to the SDRAM, enable caches, and run a primitive
"shell" over the serial link. That shell can then accept program
binaries, execute them, then return control to itself whether the
executed binary completes successfully or crashes. The shell and the
user program should execute (for now at least!) in supervisor mode (SR
bit 31==0, bit 29==1).

The problem comes when trying to return control from the exception
handler. It appears that all exceptions and interrupts switch the
processor to exception mode, do their thing, and then use RTI to
return to the original context (processor mode and program-counter
location).

In the "gcc-teststub" branch of
https://github.com/christinaa/rpi-open-firmware), in the case of an
exception being thrown, I want to return to some particular point
earlier in the program rather than the point where the exception was
triggered: RTI reads the saved SR and PC from the stack, so (in
start.s, do_exception_recovery) I poke the address of a function
(exception_recover) that should be executed in supervisor mode into
the "PC" slot, and then that function in turn longjmps back to the
start of the shell.

This *almost* works fine, aside from one detail: the processor never
seems to leave "exception" state (bits 31 and 29 of SR both zero),
despite the RTI instruction, and no attempts to force the processor
back into supervisor mode have worked out for me so far. The shell
actually sort-of works just carrying on in exception state (with
interrupts enabled, bit 30), but e.g. the exception stack and the
normal stack get all intermingled, and so crashes are bound to happen.
I'd really like for it to return to supervisor state!

A small test is present in the branch "modes", here:

https://github.com/christinaa/rpi-open-firmware/tree/modes

This demonstrates the issue with a "bkpt" instruction, but according
to further experiments I've done, the same thing holds true for other
exceptions (divide by zero, illegal memory), SWI instructions, and the
system timer interrupt -- i.e., none of those events, after being
processed by an exception handler, will return the processor to
supervisor mode on RTI. The above firmware version, compiled and
copied to an SD card, will emit the following output over serial:

[...]
Breakpoint mode test:
status reg (before bkpt): 60000000
status reg (after bkpt): 40000008

We need the "after bkpt" line to read "6000...." also. Some bits of SR
are written: see that interrupts have been re-enabled. Poking the
low-order bits of SR into the appropriate slot on the exception stack
before executing RTI loads those correctly, too.

RTI *also* doesn't seem to return the processor to user mode (bit
31==1, bit 29==1), instead returning to the presumed-illegal fourth
mode (bit 31==1, bit 29==0). I can't find any hint of an "interrupt
acknowledge" signal in the graphics driver source drop, nor in
disassembly of various blobs (it isn't, at least, the VERSION
instruction, nor reading from IC0_S).

Does anyone know, or can anyone figure out, what's going on here? Some
of my lesser-explored guesses are:

1. The VC4 can't return to supervisor nor user mode after handling an
exception. That seems exceedingly unlikely.

2. A security feature is active or misfiring. Possible culprits are
that it's something to do with the sandbox registers (though I think I
understand those reasonably well, now), or the secure SDRAM regions.
I've not had much luck figuring out the latter, but there's some code
in the graphics driver drop that uses them (relying on that fairly
esoteric-looking feature for basic CPU functionality would seem
strange).

3. Or, perhaps the exception stack needs marking in some way (no hint
of that in the code available to me though).

4. Something internal to the CPU (i.e. VPU0) -- within the normal or
control registers perhaps -- is set up wrongly. Again, I can find no
hint of that. Maybe the normal stack, exception stack and GP-relative
area have to be ordered in some particular way.

5. Exceptions don't work properly unless both VPUs are running.

6. Maybe something to do with IC0_C? I'm not sure what that 4-bit
value is. Investigating that wasn't very fruitful though.

Any hints much appreciated!

Cheers,

Jules

Other related posts:

  • » [raspi-internals] VC4 processor modes and returning from exceptions - Julian Brown