Path: utzoo!utgpu!attcan!uunet!pyrdc!netsys!ames!think!barmar
From: barmar@think.COM (Barry Margolin)
Newsgroups: comp.arch
Subject: Re: PEP: Page Execution Priviledge
Keywords: access level, User/Supervisor.
Message-ID: <28881@think.UUCP>
Date: 29 Sep 88 17:55:08 GMT
References: <2550@sultra.UUCP>
Sender: news@think.UUCP
Reply-To: barmar@kulla.think.com.UUCP (Barry Margolin)
Organization: Thinking Machines Corporation, Cambridge, MA
Lines: 45

What you described is a simplified version of the ring protection
scheme used on Multics.  On Multics, each memory segment has three
ring numbers (integers from 0 to 7) associated with it, called its
write ring, its read ring, and its execute ring.  Additionally, each
process has a current ring of execution.  You can read a segment if
your ring of execution is less than the segment's read ring, you can
write it if it is less than the write ring, and you can execute it if
you are between the write and execute rings.  The read and execute
rings are normally the same, but if the read ring is less than the
execute ring then the segment is called a gate.  If your ring of
execution is between the read ring and the execute ring, and you use a
subroutine call instruction to transfer into a gate, then a ring
crossing occurs and your ring of execution is lowered to the read ring
of the segment; the matching return instruction restores the ring of
execution.  Gates also have special protection that allows them to
only be called at specified entrypoints, so that a caller can't
transfer to the instruction after some access checks are performed.

This works well with dynamic linking of subroutines.  When a routine
is dynamically linked, a shared memory segment is mapped onto the file
containing the library, and the ring numbers of the segment are taken
from its attributes in the file system (in fact, this is how ALL file
access is done on Multics -- there are no kernel interfaces that do
explicit file I/O, although there is a user-ring library that
implements various file access methods using shared segments mapped
onto files).

All supervisor data is in segments whose ring numbers are [0, 0, 0]
(this is [write, read, execute]), so that they can only be accessed
while executing in ring 0.  System calls are implemented by doing a
subroutine call to a segment whose ring numbers are [0, 0, 5], i.e. a
gate from ring 5 to 0, and most normal users run in ring 4.  A number
of privileged system operations that aren't actually part of the
supervisor are in rings 2 and 3.

There is still a need for a supervisor/user state in the processor,
though.  When you are in ring 0 you are in supervisor state, which
allows execution of privileged instructions (such as performing I/O,
or manipulating segment descriptor registers).

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar