When capability discipline is used to organize the code of an operating system or other computing platform, there are often a few tiers of capabilities which at one end are crude and dangerous, and at the other end refined and useful to the end applications of the platform.
The pattern is most often that the refined functions comprise objects that invoke less refined and more raw objects.
These rawer objects may or may not be shared by the refined objects.
I shall speak here mainly of operating systems built on bare hardware.
In Keykos and EROS the crude capabilities provide fairly direct control of hardware features.
OS kernels multiplex various hardware facilities so they may be shared by the various software components; capability kernels present these facilities as capabilities and let user mode programs derive sub-functions for distribution to those software components in need of such function.
The refined capabilities differ from the crude in that they are limited in their interactions; writing in one file cannot damage another.
The refined capabilities are also more convenient and portable; features of the underlying hardware are largely abstracted and a simple uniform function is delivered for use by the application.
General Refining Patterns
- Making one into many.
See Keykos mux pattern.
- Reducing the scope but not the nature of a facility.
E.g. the crude capability is to read and write the disk anywhere and the refined capability is to read and write some fixed portion of the disk.
- Adapting the contract some object uses to another contract so the object can be used in another context.
- Subsetting the operations that can be performed on an object, without otherwise changing behavior.
- Civilizing, Developing, Improving(?)
- Making some facility easier or more convenient to use.
- When some geometry is involved, applying a group element of that geometry to provide an alias or alibi map.
- Create Rescindable Object
Given an object X, make a new pair of capabilities X', and R.
X' behaves as X until R is invoked after which, X' is useless.
Examples from the Keykos Kernel
We start with a simple case; computer hardware generally provides some time facility to provide an interrupt at some specified future time.
The wait object was invented that could remember one such time.
Of the two orders on the object, one could set the time, and the other could wait until that time.
(One program could set the time while another was waiting.)
The BWAIT is a kernel implemented object that performs that function.
For efficiency a small fixed number of these objects were implemented in the kernel.
A wait multiplexer program was provided that, given exclusive access to a wait object, would dynamically provide multiple wait objects.
It seems that the wait object does not fit the pattern very well for the contract remains constant from top to bottom.
Multiple tiers might be used in order to account for the space that the objects consumed, or to simplify security arguments.