Task switching on Cortext-M3 crashes after IRQ
I found the problem, finally. When my SVC handler calls block to put a task on the blocked list, that task's stack only has the registers stacked by the hardware, and not the {r4-r11} that the scheduler is expecting there to be when it runs it again later.

The quick fix is to have an assembly shim for the SVC ISR that stacks and unstacks the extra registers, and to have the C zeptos_svc_isr function return a stack pointer as zeptos_schedule does. It works, but some refactoring is in order now.