beckus / qemu_stm32

QEMU with an STM32 microcontroller implementation
http://beckus.github.io/qemu_stm32/
Other
527 stars 144 forks source link

Power-on-Reset (cold reset) #31

Closed kousu closed 3 years ago

kousu commented 5 years ago

I am testing some firmware using qemu_stm32, but now it is growing and gaining state stored in flash and I would like to make sure this is preserved and handled properly across reboots. But the only way I know to reboot qemu_stm32 is to stop it and restart it -- which of course wipes out state.

I tried added -monitor stdio to the command line and then using system_reset but it just gives an error that is out of my depth and my firmware stops responding and further resets don't work.

$ qemu-system-arm -nographic -M stm32-f103c8 -serial null -serial unix:./serial.sock -m 1 -kernel firmware.bin -s -monitor stdio 

(process:11825): GLib-WARNING **: 15:42:04.853: ../glib/gmem.c:490: custom memory allocation vtable not supported
QEMU 2.1.3 monitor - type 'help' for more information
(qemu) LED Off
system_reset
(qemu) LED Off
qemu stm32: hardware warning: PLL cannot be disabled while it is selected as the system clock.
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000000
PSR=40000153 -Z-- A svc32
qemu stm32: hardware warning: HSE oscillator cannot be disabled while it is driving the system clock.
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000000
PSR=40000153 -Z-- A svc32
system_reset
(qemu) LED Off
system_reset
(qemu) LED Off
system_reset
(qemu) LED Off

If I trace what is going on with (qemu) gdbserver + arm-none-eabi-gdb -ex "target remote :1234" then I see that the reset is triggering something, my firmware is jumping into one of its reset routines, but then it crashes before getting to main(). So I guess my firmware has a bug and cannot handle the system_reset reset, though it works fine from a cold boot.

I found https://wiki.qemu.org/Features/ResetAPI from upstream qemu (so maybe it's inaccurate) which looks like it's talking about how resets are handled in QEMU...or maybe how resets should but are not yet handled. It says

reset Bring the state of hardware state to consistent state. (some state might be left unknown.)

system reset a hardware mechanism for setting or returning all hardware states to the initial conditions.

cold reset(power on reset) system reset following the application of power.

warm reset system reset without cycling the supplied power.

bus reset Reset bus and devices on the bus.

device/function reset Reset triggered by sending reset command to a device. This is bus/device specific.

hot reset Qemu doesn't emulate physical layer, so we don't care it. From software point of view, hot reset has same effect to warm reset.

Do you know what kind system_reset does? Is there any support for cold resets? Or, is there a way to shutdown but reload a flash memory dump?

I don't know what people normally do for testing firmware. I've learned that the Gnuk/chopstx codebase doesn't have virtual tests, it assumes it is testing a hardware device plugged in over USB: https://salsa.debian.org/gnuk-team/gnuk/gnuk/blob/master/tests/conftest.py. What do you think Pebble did before they shut down? Surely they must have had a ton of weird tests handling all sorts of stateful cases.

kousu commented 5 years ago

The other embedded stm32 QEMU fork claims

The emulator currently does not preserve a persistent state of the flash memory between runs; instead, it starts with an empty flash and preloads it with the content available in an ELF file.

so if even they don't allow preserving state between runs, probably no one does.

beckus commented 5 years ago

Sorry, but I am not familiar with the reset functionality. Based on the quote I agree state preservation is probably not implemented. I am also not familiar with how this testing is done normally in the real world. Maybe these types of things are just done on real hardware. Perhaps it is possible to hack the QEMU source code to save the flash during shutdown...

lcgamboa commented 4 years ago

The current version does not reload the PC and SP value at reset. This is because qemu using the -kernel option only updates these values on the first (automatic) reset, the file is loaded as a qemu rom, but on the second reset it no longer exists. Then the error that you reported occurs.

I added support for loading the firmware via a flash drive and added support for reset. I opened a pull request: https://github.com/beckus/qemu_stm32/pull/36#issue-456788121

For the reset to work it is necessary to update the PC and SP values as done in the flash reset function: https://github.com/lcgamboa/qemu_stm32/blob/c79dc96f331271ca00ff5d30b94c9f0ff3b0bf8d/hw/arm/stm32_flash.c#L127

The reset I implemented only updates the value of the PC and SP, it does not reload the firmware of the file again.

It is possible to save the flash memory to a file, but as the support for writing to the flash is not implemented yet it will not help much. This would be useful in case of sending firmware by bootloader to qemu and saving the current state for the next run.

Qemu's system_reset currently resets the cpu and runs the reset functions of all machine components. (if the component has a reset function defined)

kousu commented 4 years ago

Thanks so much for taking that on @lcgamboa. I believe Pebble were using qemu to test their firmware, but no one else was, and then they went under so their code kind of languished. This was beyond my ken but thank you for picking it up.

lcgamboa commented 4 years ago

I updated the code to unlock the flash memory for writing. It is now possible to write on the flash, the flash content is kept between resets. This should allow yours tests and the use of serial bootloaders. The flash is not saved to a file when turning off QEMU but it is possible dump the memory using the qemu monitor interface. I don't know much about ARM microcontrollers or QEMU, but I have a lot of experience programming simulators, 8-bit microcontrollers and DSPs. The QEMU documentation is almost none and doesn't help much, but I'm having fun.

beckus commented 3 years ago

Thank you @lcgamboa for addressing this. I finally merged your pull request.