I am not sure I follow this completely. Are you sayin that the region of size 0x20000 and address 0x08020000 does not cover last 0x3E000 bytes (and as a result those 0x3E000 bytes fall in region 0)? If so, that is okay.
Can you try disabling any caches you have and see if this fixes your problem?
Apologies for missing that and thank you for clarifying.
One possible reason is that an MPU region setting is turning off cache during context switch while it has not been flushed. I have seen this once. Double check all the settings for all your MPU regions.
Not sure it is related to your problem. I had somewhat similar problem on different CPU architecture and with MPU disabled and no cache. The problem was a race condition between the pending of an interrupt to interrupt controller and subsequent code flow after portYIELD() call. You may look at this aspect.
It is possible that the problem is not a cache but just an interrupt controller latency.
That yield is asynchronous — it only takes effect when CPSR.I is clear. But the kernel does things like:
taskYIELD_WITHIN_API(); /* pends SSI IRQ */
taskENTER_CRITICAL(); /* masks IRQs a few instructions later */
so the requested switch never happened at the point where the kernel requires it, and the waiting task was left unscheduled → “lost” notification.
Fix: delete our definition and let the kernel default apply, i.e. portYIELD_WITHIN_API() → portYIELD() → SWI #0. An SWI is an exception, not an interrupt, so it cannot be deferred by CPSR.I and switches synchronously. The extra portYIELD_WITHIN_API() we had added to tasks.c is reverted. Confirmed stable, and it’s actually cheaper than the SSI path (no VIM round-trip, no flag clear).