Writing a multitasking operating system for a processor without MMU
It's actually not that hard to design an operating system that doesn't require an MMU. There are a few conveniences you'll have to do without, but nothing insurmountable.


Since different tasks will have to be loaded at different addresses, all your code (except for the kernel, the standard library, and any other code that's part of your base runtime environment) has to be compiled as position-independent. This means relative jumps and a base address for heap access stored in a register. Spending one register as a base address might seem costly if you're used to x86-32's four general registers, but most modern architectures have more, and even 8088 has the segment registers precisely for that.
A Unix-like architecture has to be revised, because you can't implement fork. That's ok, most operating systems don't have fork. (You can have vfork.)
You can't preallocate large gobs of space without also allocating the corresponding memory. This means no growing of the stack or heap on the fly by allocating one more page at a time.


If you have an MPU, then your tasks can still be separated from each other as usual in multitasking operating systems. Without an MPU, memory separation can only be cooperative if you allow tasks to execute arbitrary code. One way to achieve memory separation without an MPU is to restrict tasks to use only verified code on a virtual machine and implement memory protection in software as part of the VM engine.

uClinux is a project based on the Linux kernel that runs on processors (including ARM Cortex-M) without an MMU. Its restrictions on multitasking are essentially what I outlined above.