Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Apr 95 12:08:44 MDT
From:      terry@cs.weber.edu (Terry Lambert)
To:        mycroft@ai.mit.edu (Charles M. Hannum)
Cc:        toor@jsdinc.root.com, geli.com!rcarter@implode.root.com, hackers@FreeBSD.org, jkh@violet.berkeley.edu
Subject:   Re: benchmark hell..
Message-ID:  <9504251808.AA00479@cs.weber.edu>
In-Reply-To: <199504250710.DAA08689@duality.gnu.ai.mit.edu> from "Charles M. Hannum" at Apr 25, 95 03:10:17 am

next in thread | previous in thread | raw e-mail | index | archive | help
>    The BSD model
>    for the actual switch itself is very close to the UnixWare/Solaris model,
>    but is missing delayed storage of the FPU registers on a switch.
> 
> Speak for yourself, please.  NetBSD has been doing delayed switching
> for a while now.

Part of my campaign to refuse to acknowledge factions in the BSD camp.
You'll also notice a studious lack of "we", "us", "they", "our", and
"them" when discussing relative issues.

> That depends on what you mean by a `switch'.  You still have to set
> the `task switched' flag on a switch out, and take a fault next time
> something uses the FPU.  You could recognize that the process you're
> switching into was the last one using the FPU and automatically turn
> off the flag when switching back in.  Currently, I don't do that,
> though I may change that RSN.

Yes, recognising that the cache contents aren't stale is an obvious
optimization.

You don't have to take a fault if a fault condition has not occurred.
The main issue is that FPU using processes are less frequent than those
that do use the FPU.

> You only need a `FPU was used' flag per process if you're doing
> delayed initialization.  For primarily integer-only applications,
> delaying the FPU initialization would be a win (albeit a *very* small
> one), but it would require an extra test in the FPU context switching
> code, which would be a smaller but frequent hit for FPU-intensive
> applications.

I agree.  But I was not suggesting delayed initialization, I was suggesting
an initial run-time trapping of the first FPU instruction for a process
by redirecting the interrupt when switching in a process that hasn't
used the FPU.  The alternative would be flag generation by the linker
in the executable header to indicate an FPU using process (even if the
code path is never hit -- for instance the "printf" shell command or
whatever that is floating point capable but not necessarily floating
point active).

The point would be that you would pretend not have an FPU, trap to
what would normally be emulation code, fixup the flag on the process,
fixup the pointer on the trap code to point to the real FPU or the
emulator, depending on the box, then restart the operation.  This is
tanatamount to the runtime linking which occurs in the shared library
symbol resoloution fixup.  If it is determined that another process
was using the FPU prior to this, you save the context there, as if the
flag had been set.

The idea here is that by default, processes are assumed to not use the
FPU, and thus by default the FPU trap results in code fixup rather than
FPU operations.  Thus it does not matter which FPU operation is used
first.

> (With a slight kluge, it may be possible to combine this with the
> check for whether you're using the emulator or not, and eliminate the
> extra bit altogether.  I'll have to try this.)

I think this is entirely feasable (see above).  The question becomes
the same as that for dynamic linking, which is are you going to eat a
runtime penalty for doing this or a link time penalty.


[ ... split page protection/domain crossing (copyin/copyout/copyinstr) ... ]

> And it is precisely this that will screw Linux for SMP systems.  What
> if someone else changes a page protection after you've already checked
> it for `security'?  Answer: You don't need a programmer error to
> create a security hole.

I disagree.  The page protection check is only applicable to a region
of memory in the user process -- the target of the operation.  The only
issue you need to worry about is additional kernel processes operating
in the user domain of the process (not the kernel domain).  This is
because the only allowable source/target for the copy operations is
a user space buffer.

The worst that can possibly happen is that the user process is crashed
*if* the user process is multithreaded *and* the threads map to multiple
*kernel* threads *and* the system is SMP or kernel preemptive.  And
even then, the only thing that can do the crashing is a thread in the
process itself.

The only place this is a danger is in a hosted non-preemptive multitasking
OS, and they are already notorious for lacking memory protection domains
internally anyway in their non-hosted incarnations (NetWare, Windows).

> The region of memory needs to be locked between the time the security
> check is done and the last use of it.  There are a few ways to do
> this:
> 
> 1) Only run on single-processor machines.
> 
> 2) Only allow one processor to be executing in the kernel at a time.
> 
> 3) Lock all memory mapped by a process when it enters the kernel, and
> unlock it when exiting the kernel (being careful about the case of the
> process dying, of course).
> 
> 4) Lock memory when it is tested by verify_area(), and unlock it when
> exiting the kernel.  (This is the `best option' in Linux, without
> changing the interfaces.)

This is actually the best option, period.  The BSD "suggested" mechanism
below still allows problems in a kernel multithreaded environment.  This
is because there is assumed state to the operation for which the memory
is being protected.  In a single tasking non-preemptive kernel, you
are implicitly protected for assumed state by the fact that you will
run to logical completion rather than being preempted during a reentry
of the same code.  The use of multiple processers in the kernel is
exactly analogous to kernel preemption, and the only real difference
in implementation is the synchronization primitives being mutexes
instead of semaphores to ensure interprocesser synchronization instead
of intraprocesser synchronization between multiple threads of control.


> 5) Lock memory only for the duration of a copy operation.  (This is
> what the BSD interfaces suggest doing.)
> 
> Given that the BSD kernel is carefully tuned to limit the number of
> situations in which repeated accesses are done to the same user memory
> region, and that such tuning is fairly easy to do, the last option is
> definitely the most attractive.

I would argue that this is intrinsically limited by the processes
themselves on a locality of reference basis.

Further, I'd argue that splitting the kernel and user protection domains
while in the kernel resolves the issue quite nicely.  Instead of checking
the legality of the operation, you proceed with the operation, and if you
aren't on an i386, if it's illegal, you'll get a fault and if it's not,
the operation will be significantly faster than prophalactic checking
would cause it to be.

One result of this is that calls must take care to not take both a read
and a write argument from user space, since there is no distinction
between protection domains from an allowability standpoint, only the
verification that they are indeed different.  This resolves the illegal
read address hole that typically shows up in a poor protection environment.

You can achieve this rather simply by never mapping the user portions of
the address space simultaneously -- you run each of your contexts in
seoerate domains.

The logical side effect of this is the creation of an additional protection
domain for the kernel seperate from the domain in which copy operations
take lace.  That is, movement between protection domains is externally
arbitrated.

This is one of the things the Chorus microkernel does that results in it
being significantly lower overhead than Mach.  Mach suffers from an
overabundance of domain crossing and domain checking in the crossing.


					Terry Lambert
					terry@cs.weber.edu
---
Any opinions in this posting are my own and not those of my present
or previous employers.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9504251808.AA00479>