UP
A Quick Introduction
Segments provide the address space for programs. Segments
also provide long-term storage for data. It is a single
level storage construct for Gnosis. A segment merely organizes
4K pages into an array.
A .segment is an object acting as a definite size array of
bytes indexed from 0.
The .memory key to the segment provides access to the bytes
of the segment. Such a use of a key is called a memory reference.
The .page is a special primitive 4K byte segment whose memory
key is called a "page key". All 4K bytes of the page are
valid to access. The 4K bytes of a page are distinct from
each other and from the bytes of other pages. {This means
that storing into a byte of a page doesn't affect any other
byte of this page or any byte of any other page. This isn't
true of some segments.}
There is a null memory key. {DK(0) will do.}
From a memory key you may get a read-only memory key that
may be used to read but not to write the same segment.
Constructing Segments
For some number P that you choose which is a power of
16 and at least 64K you can create a new black segment of
size P. You get the service key and the memory key to your
segment.
The segment has 16 slots inside accessible by the service
key. An access via the memory key to some P/16 sized part
of your segment has just the effect of an access via the
key from the corresponding slot inside the segment.
The memory keys inside a newly created segment are all null.
Two constructed segments may include the same memory key.
In such a case some storage is shared between these two
segments. A store into one segment is visible in both.
An Easy Example
Choose P as 64K. Create a segment and use the service
key to install keys to 16 new pages. You now have a 64K
segment.
Advice to the Reader
The following procedure is recommended for learning about
the memory tree.
First, read (p1,memtreeparts).
Then, study simple examples, if there be examples {(p1,rab)
& (p3,vcsklogic) for
now}.
Then, read (p1,memtreeformal),
omitting sections dealing with errors and window keys.
Then, read about window keys.
Then, read about errors with codes 1, 3, and 5, and about
handling of errors. {These error codes are ones that are
expected to occur in normal operation})
Parts of the Memory Tree
Formal Description
of Memory References
{nonref}Aspects of the Memory Tree
The following miscellaneous notes are a consequence of
the foregoing.
Changing the Memory Tree
Gnosis uses the segmentation and paging tables to provide
the illusion that every access to core is via the memory
tree. This means that changes to the memory tree take effect
immediately.
The Memory Key
The memory key is a page key or segmode key. The memory
key provides the opportunity to cause some data to appear
in one's virtual storage. Placing the memory key in a memory
tree slot causes the data to appear at that address. In
addition there may be a program, the (_segment keeper),
associated with the key that the holder may be more or less
aware of. Besides fetching and storing from the addresses
defined by the memory key, the holder can call the segment
keeper concerning anything of mutual interest. There is
no general assurance that the data provided by the memory
key will not change without the key holder changing it.
The no-call bit {(p1,nocall)}
can be turned on in the memory key and the key holder can
then be sure that no segment keeper is observing the pattern
of accesses.
A memory key can be transformed into another which is like
the first except that all writes to addresses described
thereby are prevented. Bit 0 of the databyte of such a
key, the RO bit, is 1. See (tp) also.
A memory key may also be transformed into another which is
like the first except that the user of the new key may not
influence the state of the structure described by the key
except by storing into the data. Bit 1 of the databyte
of such a key, the NO_CALL bit, is 1.
Being a Segment Keeper {(p1,segkeepslot)}
Normally the segment keeper key is a gate key. We call
the domain it designates the segment keeper. The segment
keeper has control over the data described by a segment
key. Because the segment keeper is given a node key to the
segment node he may delete or change data described by the
segment. The segment keeper may create the data, page by
page, when the segment user comes to use the data. This
can be done in such a way as to provide the illusion that
the data was always there. The segment keeper is able to
gather information about the user of the segment from three
sources: stores into the data, page faults in the segment,
and explicit calls to the segment keeper. Each of these
three information channels can be prevented by the segment
user. If the segment user turns on the no-call bit in his
segment key the segment keeper is unable to detect this
and is thus unable to provide the illusion that all of the
pages are there.
The segment keeper, or segment builder may incorporate other
segments given their memory key.
I (CRL) propose the following change
to the specs.
If a segment keeper is called implicitly, and concludes
the caller is to be faulted, currently its only option is
to return a nonzero return code to the fault key. This will
result in a rejected return code trap to the domain keeper.
The problem is that the domain keeper can't distinguish
this from a rejected return code from an explicit key invocation.
The CP simulator, for example, needs to distinguish so it
can decide whether to cause an addressing exception program
interrupt, or take some other action.
A second problem is that if there is more than one segment
keeper in the memory tree, the keeper farthest from the
root (the lowest) is invoked. If he causes a trap, the next
higher keeper(s) don't get a chance to intervene. E.g. if
a CMS domain has VCSK's in its memory tree, and the VCSK
returns a nonzero return code indicating it is out of space,
the keeper of the CMS domain's memory might want to translate
the error into something appropriate to CMS.
The proposal is this. When a memory fault occurs, the fault
address is stored in the domain somewhere (e.g. in the low
4 bytes of C9, the per address). Define the invocation fault_resume_key(X+i;N)
where 0 <= i < 256 and X is chosen to not conflict
with current uses. N should be a node key to the segment
node containing the segment keeper that was called when
the fault resume key was produced. This invocation means
"Treat this reference as a memory fault of type i, and don't
bother me about it again." This invocation reapplys the
address (stored in the domain) to the memory tree. But this
time no keeper below node N will be invoked. It there is
a higher keeper, it is called; otherwise a trap code is
generated. This trap code is indistinguishable from any
other (unkept) memory fault of type i, except the keeper
may produce hitherto unknown values of i.
VCSK should be changed (or a new VCSK built) to use the new
protocol. VDK will need to be changed to understand VCSK's
new way of saying "I ran out of space". What other changes
are necessary?
See (segkeepcall) for details
of keeper's role.
{arcane}See also (p2,domtool4).
{arcane}See (p3,memtree-prognotes)
for some programming notes on memory trees.
{arcane}Design Notes
A Background Key Example
Suppose that you hold a read-only segment key to an eleven
Mb segment S and you need a segment T that is like S except
for the data at address 1E6248 thru 1E6260. The addresses
of the segment range from 0 thru AFFFFF. (All numerals in
this example are hexidecimal.)
Buy a node L. Form a segment key to L with SSC=0. This key
will serve as the memory key to the constructed segment
T. Put the data key 000000FEFFB5 in slot 15 of L to serve
as L's format key. Put key S in slot E of L. The "E" of
the format key now designates S as the background key. The
"5" in the format key indicates that each of the initial
slots of this node define 1 Mb (16**5) of storage. The "B"
of the format key indicates that L's first eleven slots
are L's initial slots. They are slots 0 thru A and they
define addresses 0 thru AFFFFF. For each initial slot of
L except slot 1, put the data key 000000s00003 where s is
the slot number. These are background window keys.
Now imagine a reference to address 456789 via key T.
Since 4<B the address is within those defined by the
initial slots of L. Slot 4 of L is examined and 000000400003
is found. The "3" marks this as a background window key
and the 400000 from the window key is combined with the
remaining unused portion of the address, which is 56789,
yielding 456789 which is used to refer to the current background
key which is S. Thus address 456789 within T is address
456789 of S. Similarly for all addresses within T from
0 to AFFFFF except for addresses from 100000 thru 1FFFFF
which are defined by slot 1 of L.
Buy another node M. In each of M's slots except slot
E put the data key 0000001s0003 where s is the slot number.
Into slot 1 of L put a segment key to M with lss=4.
Refferences to T within the range 17XXXX will now be
satisfied by applying address XXXX to the key found in slot
7 of node M. That key is the background window key 000000170003
which will combine with XXXX to form address 17XXXX which
is applied to the background key which is still S. Likewise
for all addresses within T except addresses 1EXXXX which
will reach slot E of M which we have not yet filled.
Buy another node N. In each of N's slots except slot
6 put the data key 0000001Es003 where s is the slot number.
Into slot E of M put a segment key to M with lss=3.
Addresses 1E5XXX applied to T will reach slot 5 of N
to find background window key 0000001E5003 which will combine
with XXX to be applied to S, which is still the background
key. Now only addresses 1E6XXX are different for S and T.
Buy a page and copy the data at addresses 1E6XXX from
S into the page. Modify addresses 248 thru 260 of the page
as you require. Place the page key in slot 6 of node N.