Sunday, 19 October 2014

Virtualisation and Task Switching

One of the features I have wanted to include in the C65GS from early on is some sort of task switching and rudimentary multi-tasking.

Given the memory and processor constraints, I don't see the C65GS as running lots of independent processes at the same time.  Rather, I want it to be possible to easily switch between different tasks you have running.

For example, you might be using Turbo Assembler to write some code, and decide to take a break playing a game for a few minutes, but don't want to have to reload Turbo Assembler and your source code again.

Or better, with a patched version of Turbo Assembler you might want to edit in one task and have it assemble into a separate task, and switch back and forth between them as you see fit.

It would also be nice to be able to have certain types of background processing supported.  For example, being able to leave IRC or a download running in the background, with it waking up whenever a packet arrives or a timeout occurs.

For all these scenarios, it also makes sense to be able to quarantine one task from another, so that they cannot write to one another' memory or IO without permission.  This implies the need for some sort of memory protection, and supervisor mode that can run a small operating system to control the tasks (and their own operating systems) running under it.

Thus, what we really want is something like VirtualBox that can run a hypervisor to virtualise the C65GS, so that it can have C64 or C65 "guest operating systems" beneath, and keep them all separate from each other.

This doesn't actually need much extra hardware to do in a simplistic manner.

First, we need the supervisor/hypervisor CPU mode that maps some extra registers.  I have already implemented this with registers at $D640-$D67F.

Second, to make hypervisor calls fast, the CPU should save all CPU registers and automatically switch the memory map when entering and leaving the hypervisor.  I have already implemented this, so that a call-up into the hypervisor takes just one cycle, as does returning from the hypervisor.

Third, we need to make the hypervisor programme memory only visible from in hypervisor mode.  I have already implemented this.  The hypervisor program is mapped at $8000-$BFFF, with the last 1KB reserved as scratch space, relocated zero-page (using the 4510's B register), and relocated stack (again, using the 4510's SPH register).  I am in the process of modifying kickstart so that it works as a simple hypervisor.

Fourth, we need some registers that allow us to control which address lines on the 16MB RAM are available to a given task, and what the value of the other address lines should be.  This would allow us to allocate any power-of-two number of 64KB memory blocks to a task.  When a task is suspended, it's 128KB chipram and 64KB colour RAM and IO status can be saved into other 64KB memory blocks that are not addressable by the task when it is running.  This I have yet to do.

Fifth, we need to be able to control what events result in a hypervisor trap, so that background processes can run, and also so that the hypervisor can switch tasks.  The NMI line is one signal I definitely want to trap, so that pressing RESTORE can activate the hypervisor.

By finishing these things, and then writing the appropriate software for the hypervisor, it shouldn't be too hard to get task switching running on the C65GS.

No comments:

Post a Comment