Level As mentioned above, the 2200 Series uses a 36-bit segmented virtual address. The original notion of a segmented space came from the earliest implementation that emphasized code and data separation for performance and the use of shared code banks. Over the years, this expanded to provide greater flexibility of levels of sharing and far greater protection for security and reliability. Controlled access to shared data was also introduced. A virtual address consists of three parts. The high-order 3 bits define the sharing level. This is the heart of the entire addressing and protection scheme. Every thread has eight Bank Descriptor Tables (
Segment Descriptor Tables in the industry) based on B16-B23. The tables are indexed by level – level 0 refers to the Bank Descriptor Table (BDT) based on B16, level 2 the BDT based on B18, etc. The level 0 and level 2 BDTs are common to all threads in the system. Every run (process) has its own level 4 BDT, and that BDT is common to all threads in the run. Every user thread has its own unshared level 6 BDT.
Activity Each extended-mode activity (thread) always has six banks, segments, which are totally unique to it. One is the Return Control Stack, which holds information about the calling structure, including any security relevant privilege and state changes. It is not accessible by the thread except through the use of the CALL, RETURN, and similar instructions. This is a major part of the protection and reliability mechanism. Applications cannot cause bad effects by changing the return addresses or overwriting the return control stack. Another unique bank is the automatic storage bank (Activity Local Store stack). This is used by the compilers to hold local variables created within a block. It is also used to hold all parameter lists passed on a call. One of the checks made by the operating system both on its own behalf and when a call is made to a protected subsystem is to ensure that the operands are on the thread-local stack and that the thread has the right to access the memory region referenced by any parameters. Because the parameters are kept in thread-local space, there is no chance that some other thread may change them during or after validation. It is the responsibility of the called procedure to perform similar checks on any secondary parameters that may exist in shared space (i.e., the primary parameter points to a structure that contains pointers). The procedure is expected to copy any such pointers to its own local space before validating them and then to use only that internally held validated pointer. Activities may create additional segments up to the limit of the available address space (233 words = 8GW or about 36GB). This is a convenient way for multi-threaded applications to get large amounts of memory space knowing that it is totally thread-safe and that they are not taking any space away from the rest of what is available to the program. Each activity in a program has its own independent space, meaning an application with 100 activities (for example) is able to use over 800GW (>3TB) of virtual space. Basic-mode activities do not start out with any such banks, as basic-mode programs are not aware of the virtual address space, but any calls to extended-mode subsystems will cause those banks to be created.
Programs OS 2200 does not implement programs in exactly the same way that
UNIX,
Linux, and
Windows implement processes, but that is the closest analogy. The most obvious difference is that OS 2200 only permits a single program per Run (Job, Session) to be executing at a time. A program may have hundreds of threads, but cannot spawn other programs to run concurrently. There are several banks at the Program level that contain a mixture of Run (job, session) information and program information. These are control structures for the operating system. They have no access or read-only access for the program. Programs may retrieve information from some of these structures for debugging purposes or to retrieve things like the user-id and terminal-id without the overhead of a
system call. They cannot be written by the program. They contain things like the thread state save areas,
file control blocks, and accounting information. The rest of the banks are used by the program. When a program
object file is executed, the operating system obtains the bank information from the file and creates banks as needed and loads the bank initial state from the file. The simplest program has a single bank containing code and data. This is considered very bad form, but is permitted for compatibility with old applications. You can only create such an application with
assembly language. The standard compilers create one or more code banks and one or more data banks. Normally the code banks are marked as read-only as a debugging and reliability aid. There are no security concerns either way. The program can only affect itself. Each program thus has its own address space distinct from all other programs in the system. Nothing a program can do can change the contents of any other program’s memory. The OS and shared subsystems are protected by other mechanisms which are discussed below. Even read access is prohibited to OS and subsystem memory in almost all cases from code in a program. It is possible to create a shared subsystem which is generally readable, or even writable, by multiple programs, but it must be explicitly installed that way by a privileged
system administrator. Programs are initially created with only the banks specified in the object file and with a single activity. They may use system calls to create additional banks within their own program level and additional activities.
Subsystems The closest analogy to a shared subsystem is a
.dll. A subsystem is much like a program in many respects except that it does not have any activities associated with it. Instead, it is accessed by other programs and subsystems typically via a CALL instruction. In fact, a program is a subsystem plus one or more activities. Every activity belongs to a "home" subsystem, which is the program that created it. This subsystem concept is important as an encapsulation of access rights and privilege. Within their home subsystem, activities typically share common access rights to code and data banks. Code banks in the home subsystem are usually read-only—or even execute-only if they contain no constant data—but all activities will have the right to execute them. Subsystems are also combinations of banks and may contain data banks as well as code banks. All globally shared subsystems must be installed in the system by someone with appropriate administrator privileges. Subsystems may also open files. The Database manager is a subsystem which opens all the database files for its use typically with exclusive access rights. The operating system will attach its own banks to a subsystem to hold the file control tables.
OS The OS level contains the banks of the Exec. These banks are never directly accessible by either programs or global subsystems. Entry points to the OS are all handled in the same way as a protected subsystem. Calls made to the OS are always via "gates," instructions that exist for that purpose (ER = Executive Request), or via interrupts.
The Bank Descriptor Index (BDI) The next part of the virtual address is the BDI or Bank Descriptor Index. The Level field selected a particular bank descriptor table base register (B16-B23). Base registers B16-B23 are part of the activity state and are maintained by the Exec with no direct access by the activity. The Bank Descriptor tables for the program and activity levels exist within the program-level banks that belong to the operating system. The BDI is simply an index into a Bank Descriptor Table. Each entry in the table contains information about a bank. Each such entry describes up to 1MB (256KW) of virtual address space. When a larger contiguous space is needed, consecutive entries are logically combined to create a larger bank up to the maximum of 230 words. The Bank Descriptor Table Entry (Bank Descriptor – BD) gives the size of the bank (small = up to 256KW, large = up to 16MW, very large = up to 1GW). A small bank is always represented by a single BD. Large banks are represented by up to 64 consecutive BDs and a very large bank by up to 4096 BDs. Large and very large banks need not use all 64 or 4096 consecutive BDs. They only use as many as needed to provide the virtual address space required. The entry also contains upper and lower limits of allowable offsets within the bank. Virtual addresses that are outside the limits generate a fault interrupt. This allows small banks, for example containing a message, to have only the virtual space reserved for it that it actually needs and provides a debugging check against bad pointers and indices. The BD also contains a key value and access control fields. The fields indicate whether read, write, or execute permission is granted to the instruction processor (3 bits). The Special Access Permissions (SAP) applies only to activities executing within the owning subsystem (really only those with a matching key value). The General Access Permissions (GAP) applies to everyone else and is usually zero (no access). The Exec sets a key value in the state of each activity which may be changed by gate and interrupt transitions. == Protection mechanisms ==