ingoldsby@calgary.UUCP (Terry Ingoldsby) (01/20/87)
Some time ago I was asking for explanations of the direct page variables.
A friend of mine who is an OS9 guru whipped up the following informal
(and not guaranteed) information. I'm posting it to the net since others
may be interested.
Also, I've had no answers to my questions on the ACIA device driver found
in Peter Dibble's book. Peter, are you listening?
Anyway, thanks to Caveh Jalali, here are the DP docs:
************************************************************
*
* direct page variable definitions
*
* i'll try to clarify a few variables by appending a :1 or :2 to indicate a 2
* byte quantity respectively e.g. d.fmbm:2 refers to a 16 bit value (ptr in
* this case) and d.fmbm+2:2 is also a 16 bit quantity but at d.fmbm+2.
* also, i may refer to os9 level 1 as L1 and level1 revision 2.0.0 as L1r2
*
* i'll mention system mode and user mode quite frequently.
* on the coco, these are software concenpts only; the hardware is too stupid
* (cheap?) to make a distinction between the two. System mode refers to
* the cpu when it is running kernel code such as device drivers, interrupt
* handlers, executing system calls, and so on -- basically anything which
* the user relies on as being there before he runs his own code.
* when a user program is executing, we are in the user mode.
* being in the system mode allows you to execute a few extra system calls
* which are considered 'privileged', as well as changing the action of a
* few system calls -- it is erroneous to beleive that a system call
* behaves identically in ... say a device driver (system mode) and a
* user program (user state).
* there are many instances where os9 switches between user/system mode.
* here are a few such events:
* - beginning of every system call
* - end of every system call
* - beginning of every interrupt servicing routine
* - end of interrup servicing routine
* as far as doing a state transition for interrupt servicing, it is not
* done automatically. that is why it is important to user f$poll to install
* a irq service routine -- f$poll takes care of the state switching for you.
*
* what's actually involved in state switches?
* basically, os9 changes the interrupt vector (IRQ), and the system
* call vectors to different routines, so that os9 doesn't do something
* as stupid as switching from system state to system state, or user->user.
* also, the system call vectors are changed, since some system calls
* must behave somewhat differently in the system state than user state.
* this is done by changing a pointer to the approprate table, not changing
* each entry in the table of system call entry points.
*
*
org $20 reserve first 32 bytes
d.fmbm rmb 4 free memory bit map pointers
d.fmbm:2 is the start of table
d.fmbm+2:2 is end of table
these are the bounds of a (32 byte table - 256 bits on Level1)
which are used for memory allocation and deallocation -- each bit
corresponds to a os9 (256 byte)page. Think of this as being
manipulated by f$delbit, f$allbit, etc. even tho this is not
always the case.
d.mlim rmb 2 memory limit
probably intended to be the upper bound of RAM. On the coco, it is
initially the base address where the os9 kernel resides (ie os9,
os9p2, init & boot), but at some point becomes the base address where
the os9boot file is loaded -- this is probably done by the boot module.
d.moddir rmb 4 module directory
d.moddir:2 starting address of module directory.
d.moddir+2:2 end address of module directory
this is essentially an array of the following structure
struct moddir_entry {
module *address; // if zero, this is an empty slot
char unused; // always 0
char link_count;
}
d.init rmb 2 rom base address
address of init module. Would be same as register U after f$link
to init.
* the next few are interrupt vectors. no mysteries here, i hope.
* maybe i'll say that on L1r2, the hardware (rom) vectors point to the
* fexx page, from there, we branch to the 01xx page (where the hardware
* vectors used to point, and then from there, we do an indirect jump
* thru the d.xxxx vectors
d.swi3 rmb 2 swi3 vector
d.swi2 rmb 2 swi2 vector
d.firq rmb 2 firq vector
d.irq rmb 2 irq vector
d.swi rmb 2 swi vector
d.nmi rmb 2 nmi vector
d.svcirq rmb 2 interrupt service entry
interrupt handling routine. this vector changes depending on whether os9
is in system mode or user mode.-- ie it is loaded with d.sysirq whenever
you do a system call/or an interrupt is serviced, and when a user program
is executing, it contains the value of d.usrirq.
d.poll rmb 2 interrupt polling routine
interrupt polling routine. called by the same "moment" as the clock
routine.
d.usrirq rmb 2 user irq routine
d.usrirq interrupt servicing routine when a user process is running.
d.sysirq rmb 2 system irq routine
d.sysirq interrupt servicing routine when os9 is not running a user
process (this includes executing a system call issued by a user)
essentially, this inhibits the context-switching code from running,
as well as doing a user -> sys state stransition, since you are
already in system mode (particularly when servicing interrupts)
Note: let me emphasize that NO context switches occur while os9 is
running in the system state, unless specifically requested (for
example, by a f$sleep)
d.usrsvc rmb 2 user service request routine
routine which picks the post-byte from the swi instruction and interprets
it as the system call number by using it as an index into an array
of pointers to the respective functions. Note that a user<->system state
transition also occurs for the duration of the system call.
d.syssvc rmb 2 system service request routine
as above, but does not do a user->system state transition.
(and back to user after system call is done)
d.usrdis rmb 2 user service request dispatch table
points to an array of pointers which are pointers to the system call
handling routines each element in the array points to a particular
handling routine; the index into the array is determined by the system
call number.
d.sysdis rmb 2 system service request dispatch table
as above, but points to a different array, which points to the system
state system calls. OS9 distinguishes between some system calls
depending on whether they were issued in user mode or system mode.
for example i$open returns a path number in the range of 0..15, which
is an index into the process descriptor, from which the system path
number is obtained. if you were already in system mode, i$open
would return the system path number, not the index into the process
descriptor. then there are the privileged system calls. they only
appear in array pointed to by d.sysdis.
if the pointer in the d.sysdis array is 0, then the system call
does not exist -- appropriate error returned, of course.
d.slice rmb 1 process time slice count
number of ticks the current process has been alotted since it was
made active.
d.prcdbt rmb 2 process descriptor block address
pointer to the 0-block of the process descriptors... see f$all64,
f$ret64, f$find64 for description of the structure(s) involved.
d.proc rmb 2 process descriptor address
pointer to the process descriptor of the current process.
if 0, no process running (may infer from this that the cpu is idle,
or in the process of switching between processes)
d.aprocq rmb 2 active process queue
linked list of processes which are in the "run" state
d.wprocq rmb 2 waiting process queue
linked list of procs in the "waiting" state ie just done a f$wait
these procs are awakened when their child proc exits
d.sprocq rmb 2 sleeping process queue
sleeping proc. process is either sleeping indefinitely or is doing
a timed sleep. register X on that procs's stack is used as the actual
counter for the sleeping process. there is a process state bit which
indicates whether the process is sleeping indefinitely or not.
NOTE: unlink UNIX, where you just look thru an array of proc structures,
on OS9, you have to go thru these 3 linked lists to find all the
processes on the system, which still does not include your own process,
as your process ptr is in d.proc. Whenever a process is pointed to
by d.proc, it is not in any of these lists.
d.time equ . time
d.year rmb 1
d.month rmb 1
d.day rmb 1
d.hour rmb 1
d.min rmb 1
d.sec rmb 1
d.tick rmb 1
more precise counter for d.sec. on the coco 60 of these cause an inc
of d.sec
d.tsec rmb 1 ticks / second
60 ticks/sec
d.tslice rmb 1 ticks / time-slice
process will get a maximun of d.tslice ticks before another process is
considered to be made active. this is 6 on the coco... so every
100ms, another process is run (if there is another active process)
this value puts a lower bound on the nubmer of context switches that
occur in a second. It does not force an exact number of context
switches, since a (essentially) every time a process goes to sleep
it forces a context switch.
Note: a value of 6 is pretty silly on the coco. If you want some
decent keyboard response when you have more than 1 procses running,
it is a very good idea to set this value to ... say 3.
If the process happens to be ding disk IO on the RS floppy controller,
you won't get (much) keyboard response no matter what you do; but for
those who are have their coco set up with a 56K/448K ramdisk, or a
decent disk controller (hard disk?) you can just change this value
at any time without consequence.
d.ioml rmb 2 i/o mgr free memory low bound
not used to my knowledge
d.iomh rmb 2 i/o mgr free memory hi bound
not used to my knowledge
d.devtbl rmb 2 device driver table addr
pointer to device table. array of (9 on coco) elements. each element
is a device table. essentially every open device has an entry here
(one/device driver, not per device as such)
d.poltbl rmb 2 irq polling table addr
array which is interpreted by interrupt polling routine to check
on the hardware bits desired
d.pthdbt rmb 2 path descriptor block table addr
pointer to 0-block of the path descriptors. f$all64/f$del64/f$find64
are used with this pointer to get to the correct path descriptor.
d.btlo rmb 2 bootstrap low address
base address where os9boot file was loaded.
no module beyond this address will get removed from module directory.
d.bthi rmb 2 bootstrap hi address
highest address where os9boot file was loaded
d.dmareq rmb 1 dma in use flag
You see a dma chip in the coco? HINT: there isn't one.
d.altirq rmb 2 alternate irq vector (cc)
used by ccio -- this stuff is a bit messy. if i remember correctly
ccio jumps thru here to get to the next link of the daisy-chained
interrupt servicing routines.
d.kbdsta rmb 2 keyboard scanner static storage (cc)
value of U register pointing to the static storage of ccio (V.xxx region)
d.dsktmr rmb 2 disk motor timer (cc)
counter for disk motor... probably made obsolete by f$virq. i don't
use it in my disk drvier since f$virq came on the scene, but RS may
still use it?
NOTE: i had to put f$virq in ioman, so that it would be "there" before
the ccdisk was initialized; normally it is installed by sysgo.
d.cbstrt rmb 16 reserved for cc warmstart ($71)
color basic rom looks in this are for a pair of nop's, also contains
code which switches to 64K mode, as well as jumping to the appropriate
address in the kernel for a reboot? right into os9, i think.
d.clock rmb 2 address of clock tick routine (cc)
i think this is actually the scheduler, not the clock routine... anyway
called every 1/60 sec.
d.boot rmb 1 bootstrap attempted flag
new flag. it seems this is used to flag a failed boot... ie if there
is a failure to boot, this flag is set, so that os9 doesn't try to
reboot at infinidum???
d.urtoss rmb 2 address of user to system routine (virq)
new with L1r2. routine which switches from user mode to system mode.
d.cltb rmb 2 pointer to clock interrupt table (virq)
virq entries go here.
---end---
caveh.
````````````````````````````````````````````````````````````````````
Terry Ingoldsby
...!ihnp4!alberta!calgary!ingoldsby