68K User and Supervisor States
An interesting aspect of the 68K ISA is its so-
What does a computer do when it encounters an illegal instruction or an address error? The very last thing you’d want to do is just continue executing instructions sequentially. Allowing the processor to ignore the cause of the problem, reject the faulty instruction, and then proceed as if nothing had happened is not an option. The fact that an error has occurred indicates that the program has a fatal flaw and continued execution is either meaningless or positively dangerous.
The most common course of action taken by the system after detecting an error is to generate an exception, which we can regard as a call for help to the operating system. The term exception strictly includes interrupts, which are not always generated by error conditions. Interrupts are widely used to implement a computer’s input and output operations—when a device such as disk is ready to transfer data, it sends an interrupt (i.e., a signal) to the processor. The processor detects the interrupt, stops what it’s doing and deals with the disk’s request for attention. A computer interrupt is entirely analogous to a human interrupt—if you’re doing something and someone asks you a question, you stop whatever you’re doing, answer the question and then resume your previous activity.
The software that actually deals with an exception is called an exception handler
and normally forms part of the computer’s operating system. We haven’t yet introduced
the operating system formally, so a few comments might be helpful at this point.
An operating system is probably the most important piece of software that runs on
a computer, because it acts as the interface between the computer and the machine,
and it controls the system’s resources. Essentially, the operating system is responsible
for controlling the input/output devices, and the disk and memory systems. Because
the operating system coordinates all the processor’s activities, the operating system
is also responsible for dealing with errors. Clearly, the operating system itself
should be as fault-
When the processor detects an error such as an illegal op-
Many computers are capable of multitasking; that is they can run several programs (or tasks) at the same time. In reality, the operating system rapidly switches between the different tasks to give the operator the impression that all tasks are running at the same time. When one of the errors we’ve described above occurs in a multitasking system running several tasks simultaneously, the exception handler suspends the task that caused the exception and runs another task. If, however, the computer is being used in a control application (e.g., process control in industry) some mechanism must be provided either to put the system in a safe state or to wind back the system to a point from which it is able to recover. Whatever the cause of the problem, it’s almost certain that the exception handler will be part of the processor’s operating system, rather than the application program that caused the exception.
The Protected State
A member of the 68000 family of processors is always in either a user state or in a supervisor state.
The figure illustrates two possible courses of action that may take place when an
exception is generated (remember that the terms exception and interrupt are sometimes
employed interchangeably). Both these diagrams are read from the top down. In each
case, the left-
In (a) a user program is running and an exception occurs. A jump is made to the exception handler that forms part of the operating system; the operating system deals with the problem; and a return is made to the user program. In this case, the exception handler is able to deal with the cause of the exception—the exception may have been generated by a peripheral requesting attention rather than a fatal error condition.
In (b) an exception caused by a fatal error occurs and the exception handler is called. However, in this case, the operating system terminates the “faulted” user program. The operating system then runs another user program.
These figures show user programs and the operating system existing in separate compartments—this is not a fiction. We are now going to explain why user programs and the operating system sometimes really do live in different universes.
A processor can, at any instant, be in one of several states or levels of privilege. Here, we restrict our discussion to members of the 68000 family of microprocessors that have two states (i.e., levels of privilege). One of the 68000’s states is called the supervisor state and the other the user state. The operating system runs in the supervisor state, and applications programs running under the control of the operating system run in the user state.
In simple 68000-
The three big questions we’ve now got to answer are: “How does the 68000 know what state it’s in?”, “How is a transition made from one state to another?”, and “What does it matter anyway?”
The answer to the first question is easy. The 68000 has a special flag-
The next question was “How is a transition made from one state to another?” The next figure provides a state diagram describing the relationship between the 68000’s user and supervisor states. The lines with arrows indicate the transitions between states (and the text against the line explains the action that causes the corresponding transition). This figure also demonstrates that a transition can be from the current state back to the current state.
The state transition diagram shows that a transition from the supervisor state to
the user state is made by clearing the S-
If you inspect this figure, you will see that once you’re in the user state, you
can’t get back to the supervisor state by setting the S-
We can now answer the third question we asked earlier. How can the 68000’s two-
If the 68000’s user/supervisor mode mechanism were limited to preventing the user-
Security and the Stack
When students are first introduced to assembly language programs, their early efforts often crash and bring the processor to a halt. The first place they should look for the cause of such a crash is the stack. Most computers maintain a stack to manage subroutine return addresses. When a subroutine is called by means of an instruction like BSR XYZ, the address immediately after the subroutine call (i.e., the return address) is pushed on the stack. The final instruction of a subroutine, RTS (return from subroutine), pulls the return address off the stack and loads it in the program counter. The stack is, therefore, a region of memory used to save subroutine return addresses.
The processor has a special register, the stack pointer, that points to the current top item on the stack. This stack pointer is automatically updated as elements are pushed onto the stack or are pulled off the stack.
If you corrupt the contents of the stack by overwriting the return address, or if
you corrupt the stack pointer itself, the RTS instruction will load an undefined
address into the program counter. Instead of making a return to the calling point,
the processor will make a jump to a random point in memory and start executing code
at that point. The result might lead to an illegal instruction error or to an attempt
to access non-
Consider the following fragment of code (which is both badly written and contains a serious error). Don’t worry about the fine details, it’s the underlying principles that matter. The 68000’s stack pointer is address register A7.
BSR Sub_X Call a subroutine
. Return here
Sub_X ADDA.L #4,A7 Step over the return address on the top of the stack
MOVE.L (A7)+,D0 Read the parameter from the stack
SUBA.L #6,A7 Restore the stack pointer
. The body of the subroutine goes here....
RTS Return from subroutine
The programmer first pushes the 16-
When the subroutine is executed, the programmer first attempts to retrieve the parameter from the stack stepping past the return address at the top of the stack. The instruction ADDA.L #4,A7 adds 4 to the stack pointer in order to skip past the return address on the top of the stack, (b). This is a terrible way of accessing the parameter—do remember that we are providing an example of how not to do things.
The programmer then reads the parameter from the stack by means of the operation
MOVE.L (A7)+,D0, that first increments the stack pointer by the size of the operand
(4 for a 4-
This code fails because it contains an error. The parameter initially pushed on the
stack is a 16-
The 68000’s Stack User and Supervisor Stack Pointers
There’s very little the computer designer can do to prevent programming errors that corrupt either the stack or the stack pointer. What the computer designer can do is to limit the effects of possible errors. The 68000 microprocessor approaches the problem of stack security by providing two identical stack pointers—each of which is called address register A7. However, both stack pointers can’t be active at the same time—either one or the other is in use (it’s a bit like Clark Kent and Superman; you never see them together).
One of the 68000’s two stack pointers is also called the supervisor stack pointer and is active whenever the processor is in the supervisor state. The other stack pointer, the user stack pointer, is active when the processor is in the user state. Since the 68000 is always in either the user state or the supervisor state, only one of the two stack pointers is available at any instant. The supervisor stack pointer is entirely invisible to the user programmer—there’s no way in which the user programmer can modify (or even read) the supervisor stack pointer. The supervisor state programmer (i.e., the operating system) can use a special privileged instruction to read or modify the user stack pointer.
Let’s summarize what we’ve just said. When the 68000 is operating in its supervisor
state, its S-
Consider the previous example of the faulty applications program running in the user state. When the return from subroutine instruction is executed, an incorrect return address is pulled off the stack and a jump to a random location is made. Consequently, an illegal instruction error (or a similar error) will eventually occur and an exception handler will be called. The effect of an exception is to force a change of state from user to supervisor mode. The exception handler runs in the supervisor state, whose own stack pointer has not been corrupted. That is, the applications programmer can corrupt his or her own stack pointer and crash the program, but the operating system’s own stack pointer will not be affected by the error. You could almost say that when a user program crashes, the operating system mounts a rescue attempt.
The 68000’s two-
Protected Memory Space
It is possible to build a 68000-
Partitioning Memory Space
Memory space isn’t simply an academic abstraction. When the 68000 processor accesses
memory during a read or a write cycle, it sends out signals on some of its pins to
tell the rest of the system what type of memory space it is accessing. The state
of its read/write signal, its S-
In order to control the access to memory, you have to place a special hardware subsystem
between the CPU and its memory. This hardware is called a memory management unit,
MMU. Today’s processors employ an internal on-
The MMU contains a table that describes the properties of each block of memory. A system with 16 Mbytes of memory space might divide the memory into 256 blocks of 64 Kbytes (256 x 64K = 16M). This arrangement would require a table with 256 entries, one for each of the possible blocks of memory space. When an address appears on the processor’s address bus, the contents of one of the 256 entries in the MMU’s table are read to determine the type of access permitted to this block of address space. The MMU then compares the information provided by the MMU for the current memory space with the signals from the processor indicating the actual memory space being accessed. If they match, the access is legal, otherwise an illegal memory access is reported to the processor.
The MMU acts as a type of monitor or watchdog that observes addresses on the address bus and checks whether the current CPU access is legal or not. The next figure illustrates the dialog that takes place between the CPU, the MMU, and the memory system during a read or a write cycle. At the start of a memory access the CPU generates an address and sends it to the MMU together with the control signals that define the type of the access (i.e., read or write, program or data, user or supervisor mode). If the location being accessed is illegal (e.g., if it is assigned to supervisor space and a user program is attempting to read it), the MMU sends an error message to the CPU to abort the current access and to begin exception processing (and error recovery).
Dialog between the CPU, MMU, and Memory
The next figure illustrates the structure of a memory management unit that checks whether the address space currently being accessed is legal. Once again we must emphasize that the MMU performs functions other than the security mechanism that is the subject of this chapter. Moreover, the way in which memory is actually partitioned is more complex than we’ve just described.
By dividing memory space into regions of different characteristics, it is possible to provide a considerable measure of security. A user program cannot access memory space belonging to the operating system, because an attempt to access this memory space would result in the MMU generating an interrupt. Not only does the 68000 protect the supervisor stack pointer from illegal access by a user program, the 68000 + MMU combination protects the supervisor stack (and any other address space allocated to the supervisor) from illegal access.
In summary, the 68000’s user/supervisor modes, exception handling facilities, and memory management make it a very robust processor. Errors in a user program that would otherwise bring the system to a halt, force a switch to the 68000’s supervisor state and allow the operating system to either repair the damage or to terminate the faulty program. The memory management mechanism protects the operating system from illegal access by applications programs and even protects one user program from access by another. In the next section we are going to look at an interesting implication of the 68000’s user/supervisor modes.