Chapter 3. Application Development in KeyKOS

The Shape of A Domain

The most common object in KeyKOS is a domain. All programs except the kernel run in domains. A domain consists of a very large (2^48 bytes) virtual memory, general and floating point registers, and a program status word. In this sense, it is similar to a virtual machine (except that it does not have the many hardware-oriented features such as disks, tapes, printers, storage keys, etc.) or to an MVS address space. On current 370 architecture machines it is only possible to address 2^24 bytes at a time, so KeyKOS provides windowing operators to allow a domain to address various portions of its memory.

All of the keys a domain can access are accessed through its set of key registers, each one of which is called a slot. The key registers are implemented in a segregated portion of memory. This memory is not accessible to the program running in the domain through normal machine instructions. The program may invoke the keys in the same manner that programs invoke supervisor services in conventional systems. Since, in general, it is not possible to see or alter the code of the supervisor, the only way a program knows what calling SVC 1 (or the key in slot 1) does, is from the documentation. Thus, if the key in slot 3 were defined to read a line of input from a terminal, the domain program would invoke the key in slot 3 to exercise that function.

A distinct difference between KeyKOS and conventional systems is that each domain holds its own distinct set of keys. (In conventional systems, all programs of the same privilege class may execute the same supervisor service requests with the same instructions.) A key may represent the ability to interact with another specific domain. Examples are: the domain that receives information from the keyboard of a specific terminal, the domain that accesses a particular data base, or the domain that represents an instance of a data reduction program. A program must be aware of which slot contains each of the keys it holds.

In conventional systems privileged functions are typically associated with individual SVCs. These functions are implemented by the privileged code of the operating system. In KeyKOS, each function is associated with an individual key. In KeyKOS only three SVC-like instructions are used by the KeyKOS system. These three instructions are used to implement, not specific function, but, rather, controlled communications between objects. Certain primitive functions, invoked through primary keys, are implemented within the privileged-mode code of KeyKOS. All other functions, invoked through their own secondary keys, are implemented in domains. A program cannot distinguish between a primary key and a secondary key. Every domain also holds three keys automatically employed on its behalf. These keys, which are not in the key registers of the domain, are the domain keeper key, the meter key and the segment key.

The domain keeper key is implicitly invoked when an exceptional program event occurs. Such events include attempts to execute illegal or privileged instructions or program faults (e.g. SVC requests or arithmetic exceptions).

SVCs executed by a domain (with the exception of the three KeyKOS SVCs) are of no specific concern to the KeyKOS kernel. Execution of these numerous SVCs by a program in a domain causes an implicit invocation of the domain keeper key to occur. The domain keeper may interpret the event in any way desired (including simulating the behavior of another operating system). Domain keepers may also act as debugging tools.

To take any action a domain must consume resources (e.g. CPU time). The meter key associated with a domain allows it to consume resources. When a domain attempts to consume a resource, and its meter does not contain a positive value for that resource, an implicit invocation is made of a meter keeper key associated with the meter. Meter keepers may implement policies (scheduling, accounting, etc.) associated with the consumption of the resources controlled by the meter.

The segment key associated with a domain specifies the address space perceived by a program executing in the domain. When exceptional segment events occur (e.g. an attempt to reference a part of the address space for which no memory is specified, or an attempt to write to a read-only address), an implicit invocation is made of a segment keeper key associated with the segment. Segment keepers may implement memory management policy (allocation, sharing, auditing, billing, etc.).

Establishing Connections Between Domains

The keys described above provide links that allow domains to interact with objects in clearly specified ways. Consider the following example: domain A holds a key to interact with object B. When domain A CALLs object B, a new key is created and given to object B. (A CALL is one of the three forms of invocation: CALL, FORK, and RETURN.) The new key allows object B to return to domain A. Such a transaction is typical of all interactions between domains and objects. The CALLing domain may also pass a request code, a string of bytes of data, and some of the keys it owns.

A slightly more complex example may include three objects. When domain A CALLs object B, a key to return to domain A is generated as before. However, the logic of object B requires that it get help from object C. So object B can invoke object C, via its existing key, and pass along to object C the key which it had to return to domain A. When object C completes its task, it can return directly to domain A bypassing object B.

The request code in an object invocation message is typically used to request a particular function. For example, if the invoked object was a file, a request code of 1 might mean read a record, 2 might mean write a record, etc. The string of bytes of data would be used to pass the value of the record in question.

How Objects Work Together

The objects of an application system work closely together. But each is an independent unit with independent authority. When a domain invokes an object, the domain may choose to suspend its own execution until the invoked object returns, or it may continue execution in parallel. The connections between objects must be explicitly specified by the creator of the application.

When a domain invokes one of its keys, it has no way of knowing which object it is actually invoking. It can only see how that object responds to its requests. This property may be exploited in KeyKOS by the use of objects for scaffolding, transaction auditors, and transaction-oriented debuggers.

The use of scaffold objects to simulate unimplemented functions is simple to implement in KeyKOS. A scaffold object is created containing a program that responds appropriately to the necessary invocations and is used by those objects that need to invoke it. The scaffold object could contain prototype code, or could just be connected to a terminal, allowing manual simulation of the desired function. When the real object is successfully tested, it can be substituted for the scaffold object. Integration problems are substantially reduced with this architecture, for an object may not interact with another object except by explicit transactions across the inter-object interface. Therefore it is always possible to replace any object with a more sophisticated or higher performance version of the same object without jeopardizing the entire application - as long as the two objects obey the same interface protocol.

A substitute object may monitor inter-object transactions for debugging, auditing billing, or logging purposes. If a processing object holds a key to a data base object and an auditor wishes to examine the transactions between them, it is a simple matter for a user who possesses the necessary authority to splice into the connection between the two objects.

Figure 3-1

Figure 3-2

The auditor program can copy each request and pass it along to the other object. When an unusual transaction occurs, the auditor can alert security personnel, log the event, or simulate a response.

It is important to note that there is no way for either object A or B to be aware that the auditor has been installed. Thus, it is impossible for a hostile programmer to write code that works correctly when the auditor is around, but mischievously when it isn't. This ability to install an undetectable auditor is a significant deterrent to computer fraud. The same technology of splicing one object between two others can be used for debugging, journaling, accounting, etc. In each case the object that is spliced into the connection performs its service, and perhaps passes the transaction to the intended party.