Clandestiny
December 3rd, 2004, 10:28
Hi guys,
I was recently reading a paper on the old MULTICS ring architecture.
http://www.multicians.org/protection.pdf
It is rather interesting in the sense that it gives the history behind the development of the Pentium protection ring architecture which is, in fact, based upon MULTICS.
We all know that you can't call a ring 3 function from ring 0, but interestingly this seems to be "theoretically" possible. The described procedure for an upward call in MULTICS is basically the same as for the downward call (ring 3 to ring 0 for example) and is accomplished by installing a call gate. There are, however, a few caveats.
1. The calling procedure will need to copy the arguments into a segment accessible by the lesser privileged callee.
2. 2 call gates must be installed, one for the call, and one for the return to the greater privilege level.
3. Recursion is a problem becauses you would essentially need a "stack" for return gates.
Here is the excerpt from the paper that discusses these issues if anyone is interested:
"upward call occurs when a procedure executing in ring
n calls an entry point in another procedure segment
whose execute bracket bottom is m > n. When the call
occurs, the ring of execution will change to m. The subsequent
return is downward, resetting the ring of execution
to n. These cases exhibit two unpleasant characteristics
of a general cross-domain call and return that were
not present in the other cases.
The first is that the calling procedure may specify
arguments that cannot be referenced from the ring of the
called procedure. (For a downward call, the nested subset
property of rings guaranteed that this could not
happen.) There are at least three possible solutions to
this problem. Oneis to require that the calling procedure
specify only arguments that are accessible in the highernumbered
ring of the called procedure. This solution
compromises programming generality by forcing the
calling procedure to take special precautions in the case
of an upward call. Another possible solution is to dynamically
include in the ring of the called procedure the
capabilities to reference the arguments. Because a segment
is the smallest unit of information for which access
can be individually controlled, this forces segments
which contain arguments to contain no other information
that should be protected differently, again compromising
programming generality, unless segments are inexpensive
enough that, as a matter of course, every data
item is placed in its own segment. It may also be expensive
to dynamically include and remove the argument
referencing capabilities from the called ring. The third
possible solution is copying arguments into segments
that are accessible in the called ring, and then copying
them back to their original locations on return. This solution
restricts the possibility of sharing arguments with
parallel processes. None of the three solutions lends
itself to a straightforward hardware implementation.
The second unpleasant characteristic is that a gate
must be provided for the downward return. (For an
upward return the nested subset property of rings made
a return gate unnecessary.) The return gate must be
created at the time of the upward call and be destroyed
when the subsequent return occurs. If recursive calls
into a ring are allowed, then this gate must behave as
though it were stored in a push-down stack, so that only
the gate at the top of the stack can be used. The gates
specified in SDWts seem poorly suited to this sort of dynamic
behavior.
Processor mechanisms to provide dynamic,
stacked return gates are not obvious at this time.
Because of these two problems, the hardware described
in the next section does not implement upward
calls and downward returns without software intervention.
Although the same object code sequences that
perform all calls and returns are used in these cases as
well, the hardware responds to each attempted upward
call or downward return by generating a trap to a supervisor
procedure which performs the necessary environment
adjustments.
The manner in which the stack pointer register value
of the calling procedure is saved when a call occurs and
restored when the subsequent return occurs has not yet
been discussed. For a same-ring or downward call, it is
reasonable to trust the called procedure to savethe value
left in the stack pointer register by the calling procedure
and then restore it before the subsequent return, since in
these cases the called procedure has access capabilities
which allow it to cause the calling procedure to malfunction
in other ways anyway. For an upward call and the
subsequent downward return, the same convention can
be used without violating the protection provided by the
lower ring if the intervening software verifies the restored
stack pointer register value when performing the
downward return.
Cheers,
Clandestiny
I was recently reading a paper on the old MULTICS ring architecture.
http://www.multicians.org/protection.pdf
It is rather interesting in the sense that it gives the history behind the development of the Pentium protection ring architecture which is, in fact, based upon MULTICS.
We all know that you can't call a ring 3 function from ring 0, but interestingly this seems to be "theoretically" possible. The described procedure for an upward call in MULTICS is basically the same as for the downward call (ring 3 to ring 0 for example) and is accomplished by installing a call gate. There are, however, a few caveats.
1. The calling procedure will need to copy the arguments into a segment accessible by the lesser privileged callee.
2. 2 call gates must be installed, one for the call, and one for the return to the greater privilege level.
3. Recursion is a problem becauses you would essentially need a "stack" for return gates.
Here is the excerpt from the paper that discusses these issues if anyone is interested:
"upward call occurs when a procedure executing in ring
n calls an entry point in another procedure segment
whose execute bracket bottom is m > n. When the call
occurs, the ring of execution will change to m. The subsequent
return is downward, resetting the ring of execution
to n. These cases exhibit two unpleasant characteristics
of a general cross-domain call and return that were
not present in the other cases.
The first is that the calling procedure may specify
arguments that cannot be referenced from the ring of the
called procedure. (For a downward call, the nested subset
property of rings guaranteed that this could not
happen.) There are at least three possible solutions to
this problem. Oneis to require that the calling procedure
specify only arguments that are accessible in the highernumbered
ring of the called procedure. This solution
compromises programming generality by forcing the
calling procedure to take special precautions in the case
of an upward call. Another possible solution is to dynamically
include in the ring of the called procedure the
capabilities to reference the arguments. Because a segment
is the smallest unit of information for which access
can be individually controlled, this forces segments
which contain arguments to contain no other information
that should be protected differently, again compromising
programming generality, unless segments are inexpensive
enough that, as a matter of course, every data
item is placed in its own segment. It may also be expensive
to dynamically include and remove the argument
referencing capabilities from the called ring. The third
possible solution is copying arguments into segments
that are accessible in the called ring, and then copying
them back to their original locations on return. This solution
restricts the possibility of sharing arguments with
parallel processes. None of the three solutions lends
itself to a straightforward hardware implementation.
The second unpleasant characteristic is that a gate
must be provided for the downward return. (For an
upward return the nested subset property of rings made
a return gate unnecessary.) The return gate must be
created at the time of the upward call and be destroyed
when the subsequent return occurs. If recursive calls
into a ring are allowed, then this gate must behave as
though it were stored in a push-down stack, so that only
the gate at the top of the stack can be used. The gates
specified in SDWts seem poorly suited to this sort of dynamic
behavior.
Processor mechanisms to provide dynamic,
stacked return gates are not obvious at this time.
Because of these two problems, the hardware described
in the next section does not implement upward
calls and downward returns without software intervention.
Although the same object code sequences that
perform all calls and returns are used in these cases as
well, the hardware responds to each attempted upward
call or downward return by generating a trap to a supervisor
procedure which performs the necessary environment
adjustments.
The manner in which the stack pointer register value
of the calling procedure is saved when a call occurs and
restored when the subsequent return occurs has not yet
been discussed. For a same-ring or downward call, it is
reasonable to trust the called procedure to savethe value
left in the stack pointer register by the calling procedure
and then restore it before the subsequent return, since in
these cases the called procedure has access capabilities
which allow it to cause the calling procedure to malfunction
in other ways anyway. For an upward call and the
subsequent downward return, the same convention can
be used without violating the protection provided by the
lower ring if the intervening software verifies the restored
stack pointer register value when performing the
downward return.
Cheers,
Clandestiny