[comp.os.minix] MINIX memory management

m5d@bobkat.UUCP (02/03/87)

In article <1169@steinmetz.steinmetz.UUCP> davidsen@kbsvax.UUCP (william E Davidsen) writes:
>
>If you allocate a full 64k to data, there is hardware protection: you
>can't address more than that. This assures that any program which
>doesn't deliberately set out to cause problems will not modify the
>code. ...

What about a program with a bug in it?  Like "strcpy(a, b)" when "a" is
not quite what I meant?  It's real easy to make this kind of mistake;
how many times while debugging a program on a VAX (or whatever) do you
get SIGBUS or SIGSEGV?

All it takes is a bad value passed to a routine which expects a
pointer.  This won't happen in a finished program, but it's not
unlikely in a program under construction.  To me, the most irritating
thing about non-MMU systems is that a simple bug can cause me to wait 5
(or 10 or more, depending on the system) minutes to re-boot -- not to
mention possible problems with the disk.  For example, let's say I've
got a program that goes a little bonkers and writes into a memory
location that it shouldn't touch.  Let's say (by admittedly slim
chance, though not at all impossible) that the memory my program
attacks happens to contain a block of data in the disk cache waiting to
be written.  When it gets written out, BLAMMO!  My directory structure
may have just bitten the dust.

-- 
Mike McNally, mercifully employed at Digital Lynx ---
    Where Plano Road the Mighty Flood of Forest Lane doth meet,
    And Garland fair, whose perfumed air flows soft about my feet...
uucp: {texsun,killer,infotel}!pollux!bobkat!m5d (214) 238-7474

m5d@bobkat.UUCP (02/04/87)

In article <511@bobkat.UUCP> m5d@bobkat.UUCP (Mike McNally (dlsh)) writes:
>In article <1169@steinmetz.steinmetz.UUCP> davidsen@kbsvax.UUCP (william E Davidsen) writes:
>>
>>If you allocate a full 64k to data, there is hardware protection: you
>>can't address more than that. ...
>
>What about a program with a bug in it?  Like "strcpy(a, b)" when "a" is
>not quite what I meant?  It's real easy to make this kind of mistake;
>how many times while debugging a program on a VAX (or whatever) do you
>get SIGBUS or SIGSEGV?
>
>All it takes is a bad value passed to a routine which expects a
>pointer.  ...
>
> me

Duhhhhh.  Sorry.  I just realized that the worst that can happen from a
bad call to "strcpy" is that stuff beyond the logical end-of-segment
(but within 64K of the base) could get trashed.  If pointers are only
16 bits, it's hard to change the segment base value.  Duhhhhh.  Sorry
William E. Davidsen.

I just get carried away sometimes.

AH!  I could of course pass the address of a function to strcpy...
Unlikely, but possible.  I guess my point is that although it's not
real easy to crash the system, it is possible, and the results are
potentially bad (like a messed-up file system).  But this is not my
primary concern in life.  If somebody wants to use this kind of a
system, and they're happy, then so am I.

Here's a more constructive question (which may have been answered,
but I missed it if so).  Does Minix provide a graphics interface to
the screen of the PC?  It would be nice if the "plot" routines
worked.

-- 
Mike McNally, mercifully employed at Digital Lynx ---
    Where Plano Road the Mighty Flood of Forest Lane doth meet,
    And Garland fair, whose perfumed air flows soft about my feet...
uucp: {texsun,killer,infotel}!pollux!bobkat!m5d (214) 238-7474

perry@omepd.UUCP (02/07/87)

In article <1169@steinmetz.steinmetz.UUCP> davidsen@kbsvax.UUCP
(william E Davidsen) writes about the protection of parallel MINIX
processes by using the 8086 segment registers:
>
>If you allocate a full 64k to data, there is hardware protection: you
>can't address more than that. This assures that any program which
>doesn't deliberately set out to cause problems will not modify the
>code. ...

All right. Let's assume that all our little MINIX processes are well-behaved,
i.e. they don't touch their segment registers that have been set up by the
OS. Let's further assume that we have split I/D space, i.e. that code and
data/stack segments do NOT overlap. (If they do, any stray pointer can CHANGE
my code into a FAR jump or call... and here goes my protection.)

Now the idea of our poor man's hardware protection is that we never write to
the code segment, only to the DS/SS/ES segments that are identical. So we
can indeed be sure that our process never modifies its code (which is fine
because it allows text sharing and simplifies demand paging of code) and
likewise never modifies memory in other processes, including the OS. Good.

Unfortunately, the stack is part of the data segment. Remember CALLs? The
return address INTO THE CODE SEGMENT is written onto the stack and used upon
return. If, by accident (read: bug), you smear garbage over your stack, you
are liable to clobber some return address. When the return occurs, you will
happily jump to a random location in the code segment. This is likely to be
the middle of some instruction, or a constant. [You CAN put constants
in the code segment and access them with segment overrides as long as you
don't need a pointer to them!] Again, this random instruction may accidentally
modify my segment registers and clobber whoever happens to be out there.
Don't say that's unlikely. Besides the MOVs to segment registers, there
are the FAR jump, call and return instructions that all change the code
segment, the LDS and LES instructions that change DS/ES (clobber, clobber!)
and some others. Consider that at that stage, your program is executing
random code, i.e. running around in circles and screaming. When it executes
some millions of instructions per second, it has quite a chance to hit one of
those critical instructions eventually. (Of course, it can also just hang
in a closed loop.) By the way, accidentally hitting a CLI (disable interrupts)
instruction kills you too (it disables the clock interrupt that activates the
MINIX kernel!). Some other ways how random instructions can disrupt the
machine are left as an exercise to the reader.

Incidentally, there IS a way out! All we have to do is to
separate the stack and data segments. If these two segments do not overlap,
bad pointers and our other favorite bugs cannot disrupt the stack.
Unfortunately, this means that the stack is outside our 'data address space'
and can no longer be used to hold automatic variables. We would have to
split the stack into a *control stack* in the stack segment, holding
subroutine return information, and a *data stack* that is allocated in the
data segment and holds automatic variables. We'd have to use SI or DI as
a 'data stack pointer' (BP implies the stack segment, and always using
segment overrides is no fun), interfering with their use in string
instructions. Processes would become significantly larger (we'd have to
allocate 64K for the stack segment, or else a stack overflow would overwrite
something) and slower (stack management gets more cumbersome).

Note that even with split stacks, we are STILL vulnerable to undisciplined
PUSH and POP operations - a PUSH AX followed by a RETN (near return) is the
perfect recipe for a runaway program (see above). But that's nothing new -
any assembler programmer can screw up MINIX with ease, anyway, and our C
compiler just has to keep its PUSHs and POPs straight.

Oops! That's gotten longer than I intended. My apologies to those who
aren't so interested in the lower pits of the hardware. If you can see
where I went wrong, tell me. Flames per mail, please.
  -- perry
------------------------------------------------------------------------
  <<  Perry The Cynic >>	      ...!tektronix!ogcvax!omepd!inteloa!perry
						...!verdix!omepd!inteloa!perry
    (Peter Kiehtreiber)		      -or try- perry@inteloa.intel.com