After much poking around, I finally figured out how to make this work!
The problem was that the ChibiOS initialization code had disabled
interrupts before the __early_init function was run, making the
bootloader not work despite my best intentions. This was fixed by
enabling interrupts just before jumping to the bootloader. This in turn
required changing to GNU-flavored C11 to include an inline assembly
instruction.
Based on the RT-STM32F072-DISCOVERY demo from ChibiOS/demos/STM32. The
board definition was made with the Eclipse plugin, and is based on the
ST_STM32F072B_DISCOVERY board definition from ChibiOS/os/hal/boards.