ModeMechanism.tioga
Last Edited by: Sindhu, March 27, 1985 9:37:14 pm PST
Pradeep Sindhu August 14, 1986 11:40:10 pm PDT
McCreight, December 17, 1985 11:25:53 am PST
THE DRAGON MODE MECHANISM
THE DRAGON MODE MECHANISM
THE DRAGON MODE MECHANISM
DRAGON PROJECT — FOR INTERNAL XEROX USE ONLY
DRAGON PROJECT — FOR INTERNAL XEROX USE ONLY
DRAGON PROJECT — FOR INTERNAL XEROX USE ONLY
The Dragon Mode Mechanism
Release as[Indigo]<Dragon>Documentation>ModeMechanism.tioga, .press

© Copyright 1984, 1985 Xerox Corporation. All rights reserved.
Abstract: Dragon processors use the notion of privilege to provide protection in the context of multiple address spaces. Each processor operates in one of two modes, kernel and user, with kernel mode being the privileged one. This document specifies how the mode mechanism works.
XEROX  Xerox Corporation
   Palo Alto Research Center
   3333 Coyote Hill Road
   Palo Alto, California 94304



For Internal Xerox Use Only
Contents
1. Introduction
2. Privileged Mode
3. Mode-Based Protection Checks
4. Mode Switches
1. Introduction
A key decision in the design of a multiple address space architecture is how to handle the kernel—the software that multiplexes processors between address spaces and provides other common low-level functions. In Dragon the kernel is put inside each address space in order to make round trip kernel calls fast (a discussion of some design alternatives and why they were considered undesirable for Dragon may be found in [Indigo]<Dragon>Documentation>MapProcessor.tioga). Current estimates indicate that a null round-trip kernel call will be less than 10 machine cycles, making it considerably faster than in earlier machines.
Given this decision, protecting address spaces from one another boils down to ensuring three things: (i) write-protecting kernel code and kernel data from user code; (ii) prohibiting arbitrary control transfers into the kernel; and (iii) preventing user programs from executing certain sensitive instructions.
2. Privileged Mode
The simplest way to satisfy the above requirements is to provide a privileged mode within each dragon processor. When the processor is in kernel mode it is allowed to access all of virtual memory and permitted to execute all instructions. In user mode, programs are prohibited from writing into the area of virtual memory reserved for the kernel, from directly modifying the current mode, and from executing I/O instructions reserved for the kernel.
Since user mode programs cannot change the mode directly, a special instruction must be provided for invoking kernel functions. This instruction transfers control to the kernel and simultaneously switches to kernel mode. Apart from control transfers initiated by traps and interrupts, this instruction provides the only way to switch from user mode to kernel mode. Returns are made via a special instruction that restores the caller's mode. Since the kernel can be entered either from user mode or from kernel mode, it is necessary to stack the mode on calls and unstack it on returns. In addition to mode changes that happen during kernel calls and returns, the mode may also be manipulated directly by the kernel using a privileged instruction.
The only Dragon hardware that has any knowledge at all about mode is the IFU. The current mode is maintained within the processor register IFUStatus, and the stacking and unstacking is done onto the EU stack. To permit individual bits of the IFUStatus register to be written without reading the old value, each bit of state is implemented as two bits. The two bits always read as complements of one another with the lower order bit indicating the value of the state. On a write, the two-bit value written is interpreted as follows:
00 => leave the state unchanged
01 => force the state to a 1
10 => force the state to a 0
11 => effect undefined; it is considered impolite to write this value.
The IFUStatus register currently contains two state bits. From high to low order they are: interrupts enabled (1=> enabled, 0=> disabled) and mode (1=> user, 0=> kernel).
3. Mode-Based Protection Checks
The processor implements four protection checks based on the mode bit: virtual space checks, I/O space checks, bus hold checks, and privileged instruction checks. Both the virtual and I/O space checks are applied before a reference is sent over the P-bus so that the cache doesn't have to deal with references that are in violation. In all three cases the instruction that caused a check to fail is aborted (that is, it has no effect on processor state) and an appropriate trap is issued.
Virtual Space Checks
The first 2^24 words in each virtual address space are designated the kernel reserved area; this area will hold code and data the kernel wishes to protect. Write references from user mode are checked to make sure they do not lie in this area. All other types of references are left unchecked and may be directed anywhere in virtual space.
In the event the check is violated the instruction that issued the reference is aborted and the processor is forced to take a KRefFault trap.
Note that user code can transfer control to arbitrary points within the kernel since the kernel reserved area is not read protected. These illegal transfers cannot harm the kernel since the control transfer was not accompanied by a change of mode. They will, however, have unpredicatable effects on the user mode compuation that issued them.
I/O Space Checks
I/O space checks are similar to virtual space checks. The first 2^24 addresses in I/O space are set aside as the kernel I/O area and devices to which only the kernel should have access are placed here. IO reads and writes from user mode are checked to make sure that they do not lie in this area. All other types of I/O references are left unchecked and may be directed anywhere in I/O space.
In the event the check is violated the instruction that issued the reference is aborted and the processor is forced to take a KRefFault trap.
Bus Hold Checks
When the processor is in user mode, instructions are prevented from issuing any of the P-Bus commands that hold the M-bus (this bit requests that the M-Bus be locked until a non hold command is issued over the P-Bus). Without this check user programs could easily hang the entire system.
In the event the check is violated the instruction that issued the reference is aborted and the processor is forced to take a KRefFault trap.
PBus Protection Mechanism
The three foregoing sections are simply special cases of the general PBus protection mechanism. A PBus operation contains four interesting values: a command, an address, data, and a fault indication. The command field is eight bits long. Its low-order bit ( IN [1..2) MOD 2 ) indicates whether the command will follow read (FALSE) or write (TRUE) protocol. Its next bit ( IN [2..4) MOD 4 ) indicates whether kernel address checking is desired. Its next bit ( IN [4..8) MOD 8 ) indicates whether kernel mode is required.
The condition (kernel mode OR ((command MOD 8) IN [0..4) AND ((command MOD 4) IN [0..2) OR address>=2^24))) is checked before every PBus operation is issued. If the condition is FALSE, the processor takes a KRefFault trap and does not issue the PBus operation.
Devices like the cache avail themselves of this protection mechanism by defining the codes for their operations appropriately within the PBus command space.
Privileged Instruction Checks
Two of the instructions in the Dragon instruction set are privileged in that they may be executed only from kernel mode. In the event of a violation the offending instruction is aborted and the processor is forced to take a ResInstr trap.
SIP (Store to internal processor register)
This instruction is privileged to prevent user programs from writing into the IFUStatus register, which contains the mode and interrupt enable bits.
KReturn (Return from kernel)
This instruction is also made privileged to prevent user programs from overwriting the IFUStatus register.
4. Mode Switches
A change of mode can come about in a number of different ways: Via the KCall instruction; via KReturn; via the SIP instruction; and because of the occurrence of interrupts or traps. The details for each case are given below.
KCall
KCall is the instruction that sets the mode to kernel and transfers control to the kernel, in one atomic action. This instruction is implemented as a one byte XOP that has the following semantics.
KCall =
 {[S] ← IFUStatus; S ← S+1;
  IFUStatus ← kernelMode;
  IStack.Push(PC, L);
  PC ← XOPLocation(KCallOpCode, kernelMode)
 }
Actually the KCall transfers control to the location of the XOP with KCall's opcode, and it is up to the code at this location to transfer control to the kernel. The entry point into the kernel is specified by a 16-bit argument that is at the top of stack just before KCall is executed. Therefore the code for a kernel call would be something like the following:
LIDB #EntryPoint
KCall
Note that when control arrives at the code for the XOP the old value of the IFUStatus register is at the top of the EU stack and #EntryPoint is one below the top.
KReturn
KReturn is the logical inverse of KCall. It returns control to the PC at the top of the IStack and restores an earlier mode. It is implemented as a two byte instruction with the following semantics.
KReturn(alpha) =
 {IFUStatus ← [S]; S ← S-1;
  RET alpha
 }
Here RET alpha is the standard dragon subroutine return instruction. Note that the mode is restored according to the value that is at the top of the EU stack just before KReturn is executed. KReturn is privileged so it cannot be executed from user mode.
SIP
SIP is the instruction that allows programs to overwrite internal IFU registers. In particular, it can be used to update the current mode directly. The semantics of SIP in connection with mode changes are straigtforward once we recall from Section 2 how mode is encoded within IFUStatus. This instruction is privileged so it cannot be executed from user mode.
Interrupts and Traps
Both interrupts and traps behave like procedure calls to fixed locations within virtual address space. These locations are in the kernel reserved area, and there is a separate location for each type of interrupt or trap. In addition to the control transfer, interrupts and traps also cause a switch to kernel mode; the old mode is pushed on the EU stack. Thus these semantics are very close to those of KCall:
Interrupt/Trap =
 {[S] ← IFUStatus; S ← S+1;
  IFUStatus ← kernelMode;
  IStack.Push(PC, L);
  PC ← TrapLocation(TrapType)
 }
5. XOP Semantics
XOP semantics depend on the current mode but they are different from those of either KCall or traps. Essentially, an XOP is a procedure call that involves no mode switch but for which the call's target address depends on the current mode. Furthermore, this target address lies in kernel reserved area if the current mode is kernel and outside this area if the current mode is user. Thus the XOP semantics are:
XOP(args) =
 {[S] ← args; S ← S+argsize;
  IStack.Push(PC, L);
  PC ← XOPLocation(XOPopcode, mode)
 }
These semantics allow separate XOP routines for kernel and user while permitting XOPs to be fast in both cases. Any scheme that has just one set of call targets and tries to provide different code for the user and kernel cases will incur a performance hit for both of them.