SUBSYSTEMS: Directory Control, Segment Control
Segment -- permanent storage on disk for a segment is comprised of
Directory Entry (entry)
Virtual Segment of a Process -- described by a
A program running in a user process can ask the Multics supervisor to connect a particular non-directory segment to one of the process' virtual segments (region in the process workspace directly accessible to a program). This supervisor service is called "initiating a segment" or "making a segment known to the process".
A request for the make-known service begins when the program running in
a process calls the initiate_file_ subroutine (or calls one of the
supervisor gate entry points: hcs_initiate or hcs_initiate_count).
These routines all invoke one of the supervisor entry points in
initiate_.pl1 with directory and entry arguments giving a target
pathname identifying a non-directory segment. initiate_ is part of the
Segment Control subsystem.
The supervisor must complete the following tasks to connect the target
segment to one of the virtual segments in the process workspace. These
include the make-known request plus a service to resolve a segment
fault when the virtual segment is referenced with an invalid SDW.
A) Make Segment Known to the Process
- Find segment information using the
directory hierarchy.
- Verify process has some access rights to segment.
- If segment is on a private LV: verify LV is mounted and
attached by the user process.
- Get KSTE and SDW structures to describe the segment.
- Re-use existing KSTE/SDW if segment already in-use by
process, or has been used earlier in the session.
- Extend seg access (if ACL/RBs now grant write access)
OR
- Describe Segment to Hardware and Supervisor
- Fill-in Known Segment Table Entry (KSTE)
- Fill-in faulted Segment Descriptor Word (SDW)
B) Segment Fault When Accessed by the Process seg_fault.gi.info
- Find segment in, or add a segment to, the
List of Active Segments in-use by the system.
- Fill-in process access rights in SDW and KSTE.
- If process rights change encacheability of the segment,
change encacheability setting in SDWs of ALL referencing
processes.
- Add SDW Trailer Record (STR) to ASTE tracking this process as
referencing the active segment
The next sections of this topic describe steps taken to perform Task A. Task B will described in a subsequent topic: (seg_fault.gi.info)
Each of the entry points in the initiate_ supervisor subroutine must
get information about the target segment from its directory entry.
Arguments to initiate_ give an absolute pathname for the target segment
(dname and ename arguments).
initiate_ starts by calling the Directory Control dc_find$obj_initiate
subroutine to locate the target segment's directory entry.
call dc_find$obj_initiate (dname, ename, entryp, code);
dc_find recursively calls makeknown_ to add to the process each
directory given in the absolute pathname beginning with the root
directory (>). This enables the process to look in each directory to
find the named subdirectory, and finally the entry for the target
segment.
Searches for a directory employ a 30-element associative memory
(pathname_am.incl.pl1 which is stored in [pd]>pds$pathname_am) to avoid
repeated searches for directories already known to the process.
For purposes of this info topic, the main elements of the directory
entry declaration (>ldd>incl>dir_entry.incl.pl1) located by dc_find
are:
dcl 1 entry based (entryp) aligned, /* Directory Entry */
...
2 uid bit (36), /* unique id of entry */
...
2 nnames fixed bin (17), /* number of names for this entry */
2 name_frp bit (18), /* relp start of name list */
2 name_brp bit (18), /* relp end of name list */
/* Both are offsets in dir seg */
...
2 pvid bit (36), /* physical volume id */
2 vtocx fixed bin (17), /* vtoc entry index */
...
2 dirsw bit (1), /* "1"b - entry is a directory seg */
/* "0"b - entry is a non-dir seg */
...
2 access_class bit (72), /* security attributes: */
/* level and category */
2 ring_brackets (3) bit (3), /* ring brackets on segment */
2 ex_ring_brackets (3) bit (3),
/* extended ring brackets */
2 acle_count fixed bin (17), /* number of entries on ACL */
2 acl_frp bit (18), /* relp to start of ACL */
2 acl_brp bit (18), /* relp to end of ACL */
/* Both are offsets in dir seg */
...
2 bc fixed bin (24), /* bit count */
dc_find verifies that the process and the ring-of-execution for the
program calling initiate_file_ (or one of the supervisor gate entry
points like hcs_$initiate_count) have at least read access to the
segment. (The level$get subroutine returns the ring-of-execution for
the program which called into the inner ring.)
dc_find then returns to initiate_ with a pointer to the directory entry
for the target segment. The parent directory of that segment is also
locked at this point.
initiate_ gathers information about this target segment into a
makeknown_info data structure (>ldd>incl>makeknown_info.incl.pl1):
dcl 1 makeknown_info aligned /* Data for makeknown_ */
based (makeknown_infop),
2 uid bit (36) aligned, /* segment unique identifier */
2 entryp ptr unaligned, /* pointer to directory entry */
2 flags unaligned,
3 dirsw bit (1), /* seg is a directory segment */
3 rsw bit (1), /* caller wants to re-use a segno */
/* used before for this seg. */
3 allow_write bit (1), /* supervisor wants to initiate */
/* seg with write permission if */
/* ACL/RBs grant such access. */
...
The initiate_ subroutine gathers the following information about the
target segment.
entryp ---> makeknown_info.entryp
entryp->entry.uid ---> makeknown_info.uid
entryp->entry.dirsw ---> makeknown_info.dirsw
"1"b ---> makeknown_info.allow_write
initiate_ then checks whether the target segment is stored:
If so, initiate_ must verify that the logical volume has been mounted on a
disk drive and has been attached by that process. The physical volume ID
(entry.pvid) is used for that purpose.
The initiate_ subroutine then calls the makeknown_ subroutine.
call makeknown_ ( addr(makeknown_info), segno, use_count, code );
This subroutine is responsible for making both directory and
non-directory segments known to the process.
makeknown_ first calls the kstsrch subroutine to check if the target
segment is already known to the process.
call kstsrch (makeknown_info.uid, hash_bucket, kstep);
kstsrch searches for a kste.uid matching the makeknown_info.uid (the
target segment's uid), using the kst.uid_hash_buckets array to speed
searching.
kste) describing that segment ismakeknown_.kstep value is returned along with a hash_bucketkste (which might be assigned by makeknown_)At this point, makeknown_ begins its changes to the KSTE structure and
SDW register using information returned by kstsrch.
"0"b ---> sdw.valid
"0"b ---> sdw.add
(36)"1"b ---> kste.dtbm
makeknown_ then updates its segno output argument, and the kste with
data from the current makeknown_ request.
kste.segno ---> segno
makeknown_info.allow_write ---> kste.allow_write
makeknown_info.entryp ---> kste.entryp
level$get() ---> ring
kste.usage_count(ring) + 1 ---> kste.usage_count(ring)
Notice that segment initiations are counted separately for each ring
in which the caller has initiated the segment.
makeknown_ finally returns its segno to the caller.
makeknown_ selects ankste in the process, threads it onto the hash list selectedhash_bucket (returned by kstsrch), and initializes that kste andsdw. No Page Table address or access data are recorded in the sdwsegno from the chosen kste is copied tomakeknown_'s segno return argument. kst.uid_hash_bucket(hash_bucket) ---> kste.fp
wordno(kstep) ---> kst.uid_hash_bucket(hash_bucket)
kste.segno ---> segno
makeknown_info.uid ---> kste.uid
makeknown_info.dirsw ---> kste.dirsw
makeknown_info.allow_write ---> kste.allow_write
makeknown_info.entryp ---> kste.entryp
level$get() ---> ring
kste.usage_count(ring) + 1 ---> kste.usage_count(ring)
(36)"1"b ---> kste.dtbm
"0"b ---> sdw.add
"0"b ---> sdw.r1, sdw.r2, sdw.r3
"0"b ---> string( sdw.access )
"0"b ---> sdw.valid
Setting kste.dtbm to (36)"1"b tells the segment fault handler (in Task
B) that it must re-evaluate the process's access to the segment.
For a description of the PL/I wordno builtin function, use the Multics
help command:
help pl1_new_features
Information in the "Known Segment Table (KST) header" describes the
range of the process' workspace. The array of "Known Segment Table
Entries (KSTEs)" describes each virtual segment in-use by the process
(outside of the ring-0 supervisor segments).
Main elements of the kst and kste structures (>ldd>incl>kst.incl.pl1)
are declared as follows:
dcl 1 kst aligned based (kstp), /* KST header */
2 lowseg fixed bin (17), /* lowest segment number */
/* (seg 230 = stack_0) */
2 highseg fixed bin (17), /* highest segment number */
2 highest_used_segno fixed bin (17),/* highest segment no used */
...
2 free_list bit (18) unaligned, /* relp to 1st free kste */
/* Offset in kst seg */
...
2 uid_hash_bucket (0 : 127) bit (18) unaligned,
/* hash buckets */
2 kst_entry (0 refer (kst.lowseg):0 refer (kst.highseg))
aligned like kste, /* kst entries */
...
dcl 1 kste based (kstep) aligned, /* KST entry */
2 fp bit (18) unaligned, /* forward relp to thread of */
/* KSTEs in a uid hash bucket*/
/* list or free KSTE list. */
2 segno fixed bin (17) unaligned, /* segment number */
2 usage_count (0:7) fixed bin (8) /* outstanding initiates/ring */
unaligned,
2 entryp ptr unaligned, /* branch pointer */
...
2 uid bit (36) aligned, /* unique identifier */
2 access_information unaligned,
3 dtbm bit (36), /* date time branch modified */
3 extended_access bit (33), /* extended access from entry */
3 access bit (3), /* rew */
3 ex_rb (3) bit (3), /* extended ring brackets */
...
2 flags unaligned,
3 dirsw bit (1), /* directory switch */
3 allow_write bit (1), /* initiated w/ write mode */
The main elements of the SDW structure (>ldd>incl>sdw.incl.pl1) for
this topic are:
dcl 1 sdw based (sdwp) aligned, /* Segment Descriptor Word */
(2 add bit (24), /* absolute address in hardware memory*/
2 (r1, r2, r3) bit (3), /* ring brackets for the segment */
2 df bit (1), /* "0"b = seg ^valid (directed fault) */
/* "1"b = seg valid (no fault occurs)*/
2 df_no bit (2), /* "00"b = fault treated as seg fault */
/* END OF WORD 1 */
...
2 access, /* access bits: */
/* a running program can... */
3 read bit (1), /* "1"b = read seg's bits/chars/words */
3 execute bit (1), /* "1"b = execute or transfer to seg */
/* words as instructions */
3 write bit (1), /* "1"b = write seg's bits/chars/words*/
3 privileged bit (1), /* "1"b = seg holding running program */
/* can include "privileged */
/* instructions" only allowed*/
/* in ring-0 supervisor code.*/
...
) unaligned;
When initiate_ returns to its caller, the process has initiated the target segment. The segment's SDW has some data but may not be valid for use by the hardware unless the segment was previously known to the process, and write access had been granted earlier. If the SDW is not valid, the first time any program in the process tries to reference that SDW, a segment fault will occur.
The next topic explains steps taken to complete Task B (outlined above) which resolve the segment fault by connecting the SDW to an ASTE and Page Table describing the "activated" target segment. To display that info block, select the link: seg_fault.gi.info