1 Introduction
2 Ground Rules

Building a File System
3 File Systems
4 File Content Data Structure
5 Allocation Cluster Manager
6 Exceptions and Emancipation
7 Base Classes, Testing, and More
8 File Meta Data
9 Native File Class
10 Our File System
11 Allocation Table
12 File System Support Code
13 Initializing the File System
14 Contiguous Files
15 Rebuilding the File System
16 Native File System Support Methods
17 Lookups, Wildcards, and Unicode, Oh My
18 Finishing the File System Class

The Init Program
19 Hardware Abstraction and UOS Architecture
20 Init Command Mode
21 Using Our File System
22 Hardware and Device Lists
23 Fun with Stores: Partitions
24 Fun with Stores: RAID
25 Fun with Stores: RAM Disks
26 Init wrap-up

The Executive
27 Overview of The Executive
28 Starting the Kernel
29 The Kernel
30 Making a Store Bootable
31 The MMC
32 The HMC
33 Loading the components
34 Using the File Processor
35 Symbols and the SSC
36 The File Processor and Device Management
37 The File Processor and File System Management
38 Finishing Executive Startup

Users and Security
39 Introduction to Users and Security
40 More Fun With Stores: File Heaps
41 File Heaps, part 2
42 SysUAF
43 TUser
44 SysUAF API

UCL
45 Shells and UCL

Glossary/Index


Download sources
Download binaries

Overview of The Executive

The Component Approach
With this article we begin our exploration of the UOS Executive. When we were writing the UOS File System, we were able to build it up slowly with one class build upon another, in "layered" fashion. Each layer relied upon the features of the layers beneath it. This provided us with a simple and incremental approach to coding the file system. Each layer that we developed provided a more abstract means of accessing the lower layers. At the lowest layer, we are accessing sectors on a store, while at the highest layer, we are accessing files in a file system. Much of programming - regardless of the application - is a matter of abstraction.

Sometimes the layering approach is referred to as a "stack". I don't use that term for this approach, as it might lead to some confusion with the LIFO data structure of the same name. Instead, we will use the above terminology for this architecture - layered. However, we cannot take this same approach with the executive. This is because the various components that make up the executive all rely on each other. There is no hierarchical structure here other than that the kernel is at the center, not unlike a spider at the center of a web. The components are marshalled (loaded and setup) by the kernel. Once they are running, however, they all operate semi-autonomously. Each one has a specific scope of responsibility and they all work together to serve up the executive's functionality. The following diagram helps to illustrate the difference between these two architectures.

Because of this organization, we can't approach the subject as we approached the file system. Rather, we will look at specific operations and follow the trail through the various components that are necessary to accomplish the task. We will only expose enough of each component as is necessary to accomplish the operation.

In this way, we can explore various aspects of UOS without getting lost in the complexity. As we complete our discussions of various operations, we will release new binaries and sources (and documentation). Be warned - it may take us a great many articles to address even the simpler operations.

What we call the UOS "executive" is equivalent to what is called the "kernel" in most operating systems. "Executive" is short for "Exceutive Monitor", which is what they used to called kernels back in the dark ages of computing. We use this term to avoid confusion with the central component in the executive, which we call the Kernel. The executive is layered on top of the HAL, which is used to access the specific hardware of whatever computer UOS is running on (just as does Init). The kernel provides two main services: it marshals the rest of the executive components, and it provides the Application Program Interface (API) for all programs that run on UOS. That is, the kernel is the single point of access to the functionality of the executive for all software that is outside of the executive. Within the executive, the various components ask the kernel for the instances of the other components and then directly call each other. Here is a brief list of executive components:

  • Kernel - API
  • USC - User and Security component
  • FiP - File (and device) Processor
  • SSC - System Services component
  • IMC - Interrupt Management component
  • HMC - Heap Management component
  • MMC - Memory Management component

Let's review the reason why we use all these components in the first place. After all, couldn't we write the executive as a single software module? Yes, we could - and many operating system kernels are written this way. The reason we are using the component approach is because it makes it easier for people to supply updated or new components for UOS. For instance, perhaps some real-world use of UOS requires a high-speed memory management unit that outperforms the standard one included in public distributions. You may ask, "why not just use the high-speed component as the standard one?" Recall that software is a matter of trade-offs. Increasing the performance may have downsides such as a larger disk and/or RAM footprint. Or the component may be a commerical implementation that you have to pay for.

Even ignoring alternate versions of components, there is the need to provide updates for UOS. If the entire executive has to be replaced on an update, that requires a reboot of the system. However, if individual components can be replaced, it is possible to update the system without requiring a reboot. This is extremely important on high-availability systems where downtime has to be minimized. Maybe it cannot be completely eliminated - but we want to achieve as close to 100% uptime as possible. Finally, writing the executive in components forces us to decouple things. Modular programming is simply good programming practice, but it is extremely easy to introduce pathological coupling unless the modularization is enforced by our design. In fact, it is this (almost inevitable) coupling that makes a single-module executive updatable only via reboots.

UOS software responsibility philosophy
Now we'll take a moment to address our philosophy about what parts of UOS are responsible for what tasks, at a macro level. In most modern operating systems, the Kernel is responsible for managing security, interfacing with hardware, and providing a somewhat abstract interface for programs to access that hardware. The UOS executive is no different. The executive doesn't provide any other services for programs. For instance, it is not responsible for math function libraries, or heap management (the HMC component is solely for the use of the executive), or text processing. That is not to say that UOS doesn't provide such things - only that the part of the UOS that we call "the executive" does not. All of the non-executive functionality provided by UOS comes via system libraries and Commonly Used System Programs (CUSPs). Note that there is no difference between a program written by a user and a CUSP, other than the fact that a CUSP is supplied as part of UOS. In fact, the user is free to replace a CUSP with his own program(s) if so desired. As a whole, UOS can be viewed as a layered architecture:

The HAL and device drivers provide the physical hardware interfacing and abstraction for the use of UOS. The executive provides the core OS functionality. The CUSPs provide the interface between the executive and the user. The executive is accessed solely via a programming interface and contains no direct support for user interaction. In terms of I/O, it simply sends commands to the HAL based on requests made by programs. As can be inferred from the above diagram, requests come from higher layers to lower layers. However, there are three cases where the executive calls "up" to a higher layer.

  1. Callbacks requested by a program
  2. Startup
  3. Login
We will eventually discuss all three cases, but for now, we are only looking at startup.

This should make it clear where any given functionality belongs. We must always ask ourselves "is this a feature that should exist in the executive, or in a CUSP?" The only things that should go into the executive are things that can only go in the executive. If the functionality can go in a CUSP, it should. Security features, for instance, are implemented largely in the executive because we cannot rely on programs to be well-behaved. However, the actual login process is largely handled by the Login program, which queries the user for things like a user name and password. This input is passed to the executive to actually associate the user with the object being logged in (perhaps a terminal or a spawned process). Knowing this philosophy means we won't be including, for instance, a user name prompt inside the executive.

Now that we have discussed the architecture and philosophy of UOS, the next several articles will deal with the process of starting up the Executive. The next article will look at the first part of the kernel startup code.