Multitasking, MMUs, and Microkernels(split from BSOD thread)
Posted: Mon Mar 16, 2020 8:54 pm
Responding to Schol-R-Lea in this thread:
EDIT: Any idea what the difference between the KS-11 and the KT-11 was? In other sources I've heard the MMU for the 11/20 called the KT-11, but Dennis Ritchie's recollections call it the KS-11. I think I've heard that Bell Labs got a fairly early MMU, was the KS the beta version of the KT?
I'm also uncertain about the M68k, I thought I'd heard something about it to the effect that it had separate user and kernel modes before it had an MMU, but I've not heard of the Mac or Amiga using this to prevent userspace programs from scribbling on the kernel (OTOH, I know that the M68k had issues with not preserving enough information to allow a program to be restarted after an exception, which complicated the addition of an MMU, but most cases of a user program trying to scribble on the kernel are going to result in program termination anyway).
In which case the kernel can't restart the driver because execution can't restart until a reset occurs (unless the machine has a watchdog timer hooked to an NMI).
or
In which case the driver will hose all of memory (unless it hits an address with nothing attached and gets a bus error, but depending on the exact circumstances, it could easily overwrite the entire kernel with garbage before that happens, or the specific hardware involved may just ignore writes to non-existent memory rather than erroring out).
The first can be prevented with a user/kernel distinction that prevents the execution of privileged instructions, the second can be prevented with a user/kernel distinction and a user address limit register.
You're still vulnerable to a large class of bugs that will clobber the kernel if you don't have at least *some* protection.
My argument is that preemptive multitasking is impossible without an MMU (or at least a user address limit register like I described above). Any "preemptive" multitasking OS on unprotected hardware is in fact doing cooperative multitasking. Now, the cooperation required is passive (don't mess with the kernel), rather than active (hand control back regularly, and while you're at it, don't mess with the kernel), and it makes the task of making the system preemptive easier (you just have to add code to handle the protection hardware, which might be fairly trivial for a user address limit scheme), but it's still cooperation: a program that bugs out can do something uncooperative in its death throes and kill the system, and a program that decides to be actively uncooperative can walk in confidently with a clipboard, and say to the receptionist: "Hi, I'm the new scheduler, could you direct me to the timer interrupt? OK. OK. Down the hallway to the right, left at the hallway with the big sign: 'Interrupt vector table --- Authorized drivers only', then third door on the left? Did I get that right? Thanks!". A few hundred microseconds later, the system is under new management and the old scheduler's family files a police report as he hasn't been seen in three nanodays. Meanwhie, an unidentified core dump is found in a back alley with a gunshot wound to the head.
Strictly speaking, you don't need an MMU to have preemptive multitasking, just a user/kernel mode distinction and somewhere to put the timer interrupt vector, the timer ISR, and the scheduler that user mode can't touch (and you might as well put the rest of the kernel there while you're at it). This could be as simple as a "User address limit" register that sets the highest address accessible in user mode, and that only kernel mode can write to, no address translation is necessary.Schol-R-LEA wrote:
Well, keep in mind that this applied to almost every small computer - including several minis - prior to 1990 or so, and still applies to many modern microcontrollers as well - a number of RTOSes don't assume the presence of an MMU, and some don't use it even when present. I know that the original QNX could run on an 8088 with no MMU, for example. I imagine some of the embedded developers here could say more on this.
ISTR reading that the PDP-11/20 had a user/kernel distinction even before it had an MMU, but I may be misremembering. Stories I've heard out of Bell Labs about applications being able to bring down the system early on would indicate that I probably am.Oh, and the first several versions of UNIX ran on PDP-7 and PDP-11 systems with no MMU, as well, though they were quick to adopt it when the KS-11 add-on came around. The lack of an MMU was one of the 'vital parts' from Multics whose absence led to the operating system's punny name, If I am not mistaken.
EDIT: Any idea what the difference between the KS-11 and the KT-11 was? In other sources I've heard the MMU for the 11/20 called the KT-11, but Dennis Ritchie's recollections call it the KS-11. I think I've heard that Bell Labs got a fairly early MMU, was the KS the beta version of the KT?
I'm also uncertain about the M68k, I thought I'd heard something about it to the effect that it had separate user and kernel modes before it had an MMU, but I've not heard of the Mac or Amiga using this to prevent userspace programs from scribbling on the kernel (OTOH, I know that the M68k had issues with not preserving enough information to allow a program to be restarted after an exception, which complicated the addition of an MMU, but most cases of a user program trying to scribble on the kernel are going to result in program termination anyway).
But there's nothing to prevent a driver from hanging by doing:Indeed, one of the touted advantages of the microkernel design when people like Tannenbaum started really promoting it was that it "didn't need" hardware memory protection, since it was vastly better at both process isolation (due to using message passing for IPC rather than shared memory sections and manually-managed semaphores) and system stability (since a hung driver could be shut down and restarted without affecting the kernel itself).
Code: Select all
cli
hlt
or
Code: Select all
condition=true;
index=0;
while(condition=true) //Oops! Assignment instead of comparison!
{
array[index] = func1(param1);
condition = func2(param2);
index++; //Forgot to check that our index doesn't run off the end of the array
}
The first can be prevented with a user/kernel distinction that prevents the execution of privileged instructions, the second can be prevented with a user/kernel distinction and a user address limit register.
You're still vulnerable to a large class of bugs that will clobber the kernel if you don't have at least *some* protection.
I'm still going to try to sell it thatMy point is that, given that most of the various pre-emptive multitasking systems ever written were on systems with no MMU, saying that they weren't pre-emptive multitasking systems at all is a hard sell.
My argument is that preemptive multitasking is impossible without an MMU (or at least a user address limit register like I described above). Any "preemptive" multitasking OS on unprotected hardware is in fact doing cooperative multitasking. Now, the cooperation required is passive (don't mess with the kernel), rather than active (hand control back regularly, and while you're at it, don't mess with the kernel), and it makes the task of making the system preemptive easier (you just have to add code to handle the protection hardware, which might be fairly trivial for a user address limit scheme), but it's still cooperation: a program that bugs out can do something uncooperative in its death throes and kill the system, and a program that decides to be actively uncooperative can walk in confidently with a clipboard, and say to the receptionist: "Hi, I'm the new scheduler, could you direct me to the timer interrupt? OK. OK. Down the hallway to the right, left at the hallway with the big sign: 'Interrupt vector table --- Authorized drivers only', then third door on the left? Did I get that right? Thanks!". A few hundred microseconds later, the system is under new management and the old scheduler's family files a police report as he hasn't been seen in three nanodays. Meanwhie, an unidentified core dump is found in a back alley with a gunshot wound to the head.