.if n .pH portguide.ML @(#)ML	40.3
.\" Copyright 1989 AT&T
.BK "Programmer's Guide: Porting the Kernel"
.CH "Directory - ML" 9
.H 2 "Directory - ML"
.IX ML directory
The following notes describe the \f3ml\f1 directory, which contains low-level code.
Most routines mentioned here are machine dependent.
A porter is expected to make changes, if necessary, based on a hardware used.
.P
.BL
.LI
\f3cdump.c  -  MD\f1
.br
\f3cdump.c\f1 has support routines for taking a system memory dump after a crash.
All routines are machine dependent and any action by a porter depends on the
hardware.
.BL
.LI
\f4cdump\f1
.br
\f4cdump\f1 is called from \f4pstart\f1 to write contents of memory to
secondary storage.
\f4cdump\f1 calls either \f4flopdump\f1 or \f4diskdump\f1. 
.LI
\f4flopdump\f1
.br
The \f4flopdump\f1 routine writes crash dump to floppy.
.LI
\f4diskdump\f1
.br
This routine writes crash dump to hard disk.
A set of variables specifies which partition is to be used, and which sectors of
the partition.
These variables are initialized to a set of defaults, which are changed
by the routine \f4iddumpinit\f1 that is in \f3io/id.c\f1. 
\f4iddumpinit\f1 takes the new values from the \f2dumpdev\f1 variable,
which is generated by the autoconfiguration program \f3cunix\f1.
.LI
\f4query\f1
.br
\f4query\f1 prompts a user and reads single letter response: \f2q\f1 for quit,
\f2c\f1 for continue.
.LI
\f4nquery\f1
.br
This routine prompts a user and reads single letter response to determine where
to write crash dump.
.LI
\f4crash_timestamp\f1
.br
The routine reads time of day clock and computes time stamp for crash dump.
.LE
.LI
\f3cswitch.s  -  MD\f1
.br
This is an implementation of \f4setjmp\f1 and \f4longjmp\f1 (non-local gotos)
for kernel.
.BL
.LI
\f4setjmp\f1
.br
The \f4setjmp\f1 routine saves context and returns 0.
.LI
\f4longjmp\f1
.br
The \f4longjmp\f1 routine restores context previously saved by \f4setjmp\f1,
so that \f4setjmp\f1 appears to return a value of 1.
.LE
.LI
\f3gate.c  -  MD\f1
.br
This file defines the gate tables and process control blocks
required for trap and interrupt handling on the 3B2.
A gate is the basic 3B2 trap mechanism.
It can be caused either by an explicit \f4GATE\f1 instruction or by a so-called
``normal'' exception.
A process control block specifies a full context switch which
will take place either through explicit \f4CALLPS\f1 (call process)
or \f4RETPS\f1 (return from process) instructions, or through process,
stack, or reset exceptions.
.BL
.LI
\f4gate1\f1
.br
This is an array of pointer table entries.
The first entry, \f4gatex\f1, is a pointer to an array of exception handlers
for the so-called ``normal'' exceptions of the 3B2.
The second entry, \f4gates\f1, is a pointer to an array of handlers for system calls.
The remaining 30 entries in \f4gate1\f1 will catch any illegal gates.
.LI
\f4Xreset, Xproc, Xstack\f1
.br
These are pointers to process control blocks (PCBs) for reset, process,
and stack exceptions.
.LI
\f4Ivect\f1
.br
\f4Ivect\f1 has interrupt vectors, pointing to PCBs.
These are mostly placeholders, filled in during autoconfiguration, except for
certain required interrupt handlers, such as the clock.
.LI
\f4gates\f1
.br
This is a gate table for system call entries.
Note that all system calls enter through the \f4Xsyscall\f1 routine in 
\f3ml/ttrap.s\f1.
.LI
\f4gatex\f1
.br
This is a gate table for normal exceptions.
.LI
\f4gaten, gatefiller\f1
.br
These are gate tables for illegal system calls.
.LE
.LI
\f3kpcbs.c  -  MD\f1
.br
\f3kpcbs.c\f1 defines PCBs required by the kernel.
It also defines stacks used by the processes.
The variables defined are:
.DS
	\f4krnl_isp\f1	interrupt stack
	\f4kpcb_null\f1 	dummy PCB for spurious interrupts
	\f4kpcb_px\f1	on-process exception PCB
	\f4kpcb_sx\f1	on-stack exception PCB
	\f4kpcb_pswtch\f1	PCB used for context switch
	\f4kpcb_qrun\f1	PCB used for STREAMS scheduling
	\f4kpcb_L9\f1	level 9 interrupt PCB
	\f4kpcb_L15\f1	level 15 interrupt PCB
.DE
.LI
\f3misc.s  -  MD\f1
.br
This contains various machine language routines.
Any action by a porter depends on a hardware.
.BL
.LI
\f4addupc\f1
.br
This routine performs computation for profiling. 
It is called during interrupt or
trap handling if profiling is turned on for current process.
The arguments are:
.sp .5
.br
1. the program counter (\f4pc\f1) of the current process,
.sp .5
.br
2. the address of the \f2u_prof\f1 field of the user structure of the
current process (an unnamed structure type), and
.sp .5
.br
3. the running time of the process to be assigned at that \f4pc\f1.
.br
.sp
The routine uses the \f4u_caddrflt\f1 recovery scheme to recover if
a fault occurs while accessing the profile buffer, which is in user space.
.LI
\f4spl*\f1
.br
\f4spl\f1 sets processor priority level to a particular value.
On the 3B2, processor priority ranges from 0 (low) to 15 (high).
The following lists the new processor priority set by the different \f4spl\f1 
routines on the 3B2:
.br
.TS
allbox;
l c l.
Routine Name	3B2 IPL	Description
\f4spl0\f1	0	Allow all interrupts to be serviced.
\f4spl1\f1	8	Mask context and process switch interrupts
\f4spl4\f1	10	Mask character device interrupts.
\f4spl5\f1	10	Mask character device interrupts.
\f4splpp\f1	10	Mask ports board interrupts
\f4spl6\f1	12	Mask block device interrupts
\f4splvm\f1	12	Mask VM related interrupts
\f4splni\f1	12	Mask network interface interrupts
\f4splimp\f1	13
\f4spltty\f1	13	Mask TTY device interrupts
\f4splstr\f1	13	Mask STREAMS device interrupts
\f4spl7\f1	15	Mask all interrupts
\f4splhi\f1	15	Mask all interrupts
.TE
.br
The return value from these \f4spl\f1 routines can later be used as
an argument to \f4splx\f1 to restore the previous priority level.
.LI
\f4splx\f1
.br
This routine restores the processor priority saved by a call to \f4spl*\f1.
The argument is a value which was previously returned by
one of the \f4spl\f1 routines in the previous list.
The return value can be used by another call to \f4splx\f1 to reset the priority
level yet again.
.sp
In the porting base, the argument to \f4splx\f1, and the return from
all the \f4spl\f1 routines, is a copy of the processor status word (\f4psw\f1).
\f4splx\f1 simply loads the \f4psw\f1 with the new value to restore a
previously saved priority level.
.LI
\f4vstart_s  -  MD\f1
.br
This is the first routine executed by the kernel in virtual memory. 
It is called during the startup sequence, from the routine \f4pinset\f1 in
\f3ml/uprt.s\f1, after the virtual address mapping
for the kernel has been established.
\f4vstart_s\f1 sets up a stack frame for process 0, and then calls \f4mlsetup\f1
with a single argument of the first free memory click.
After \f4mlsetup\f1 returns, \f4vstart_s\f1
then calls \f3main\f1 (see \f3os/main.c\f1). 
\f3main\f1 forks several times; the first fork and last fork return to
\f4vstart_s\f1.
The return value from each fork of \f3main\f1 is the address of a routine to which
control is to be transferred.
\f4vstart_s\f1 transfers control to the appropriate routine by pushing a
program counter (\f4pc\f1) and \f4psw\f1 value on the
stack and doing a \f4RETG\f1 (return from gate) instruction to load
these \f4pc\f1 and \f4psw\f1 values from the stack.
.sp
\f4vstart_s\f1 checks the variable \f2u400\f1, defined in \f3os/sys3b.c\f1.
The value of \f2u400\f1 indicates whether the 3B2 instruction cache
is to be used; specifically, the instruction cache is enabled if and only
if the value of \f2u400\f1 is non-zero.
The use of the instruction cache is controlled by some
bits in the \f4psw\f1; thus, there is some code in \f4vstart_s\f1 which
checks \f2u400\f1 and manipulates the \f4psw\f1 itself, or the \f4psw\f1 value
pushed on the stack.
.LI
\f4idle\f1
.br
This routine is called when no processes are ready to run.
The system time accounting done by the clock interrupt
handler in \f3io/hrtimers.c\f1 and \f3os/clock.c\f1 needs to know when
the clock interrupt occurs during this routine.
This is done by storing in the global variable \f2waitloc\f1 the address
(\f2_waitloc\f1) of the instruction following the \f4WAIT\f1 instruction,
and comparing this with the interrupted \f4pc\f1.
.LI
\f4min\f1
.br
\f4min\f1 returns the smaller of two unsigned integers.
C declaration would be:
.br
	\f4unsigned min(a, b) unsigned a, b;\f1
.LI
\f4max\f1
.br
\f4max\f1 returns the larger of two unsigned integers. 
The C declaration would be:
.br
	\f4unsigned max(a, b) unsigned a, b;\f1
.LI
\f4rtrue\f1
.br
\f4rtrue\f1 returns TRUE (i.e., 1).
This routine supports the autoconfiguration scheme, specifically,
the program \f3cunix\f1.
.LI
\f4rfalse\f1
.br
\f4rfalse\f1 returns FALSE (i.e., 0).
This routine supports the autoconfiguration scheme, specifically,
the program \f3cunix\f1.
.LI
\f4bzero\f1
.br
\f4bzero\f1 zeros out a specified memory block.
Non-recoverable memory faults end up at \f4bzeroflt\f1, via the \f2u.u_caddrflt\f1
field.
It returns 0 on success, -1 on failure.
.LI
\f4struct_zero\f1
.br
This is an alternate name for \f4bzero\f1; present for compatibility with
routines which call the in-line assembler routine \f4struct_zero\f1
defined in \f3sys/inline.h\f1, but for some reason can't access
the in-line definition.
.LI
\f4bzeroba\f1
.br
This is an alternate name for \f4bzero\f1; present for backwards compatibility.
.LI
\f4kzero\f1
.br
This is an alternate name for \f4bzero\f1; present for VM compatibility.
.LI
\f4bcopy\f1
.br
This copies a block of memory.
Length is specified in bytes.
.LI
\f4fbcopy\f1
.br
This copies a block of memory.
Length is specified in clicks (i.e., pages).
This calls \f4fbclop\f1 with the length multiplied by 16; this is
because \f4fbcopy\f1 deals with 2048 byte units, and \f4fbclop\f1 deals
with 128 byte units (16 * 128 = 2048).
.LI
\f4fbclop\f1
.br
This copies a block of memory.
Length is specified in 128 byte units.
.LI
\f4copyin\f1
.br
This is a kernel copy-in routine.
From address is in user space, to address is in kernel space.
If process is an RFS server, then \f4copyin\f1 calls \f4rcopyin\f1 to perform
a remote copy-in from the client.
Otherwise, it calls \f4lcopyin\f1 to do a local copy-in.
.LI
\f4lcopyin\f1
.br
This is a local kernel copy-in routine to copy from (local) user memory
to kernel memory.
The comment in the code may be a little confusing, but basically the routine 
first checks that the user memory to be copied is in the valid range of user memory, 
i.e., the starting address is greater than \f4MINUVTXT\f1, and either the
ending address is before the u-block, or the whole region
is after the u-block (i.e., beyond the kernel stack of the process).
.LI
\f4copyout\f1
.br
This is a kernel copy-out routine. 
From address is in kernel space, to address is in user space. 
If process is an RFS server, then \f4copyout\f1 calls \f4rcopyout\f1 to
perform a remote copy-out to the client.
Otherwise, it calls \f4lcopyout\f1 to do a local copy-out.
.LI
\f4lcopyout\f
.br
This is a local kernel copy-out routine to copy from kernel memory to
(local) user memory.
It performs a bound check on the user address identical to that of \f4lcopyin\f1.
.LI
\f4fubyte\f1
.br
This fetches byte from user space.
On separate ID machines this fetches a data byte.
If process is an RFS server, this calls \f4rfubyte\f1 to fetch a byte from
a remote user.
.LI
\f4fuibyte\f1
.br
This fetches byte from user space.
On separate ID machines this fetches an instruction byte. 
If process is an RFS server, this calls \f4rfubyte\f1 to fetch a byte
from a remote user.
.LI
\f4lfubyte\f1
.br
This fetches byte from local user space.
Separate ID machines may need to implement \f4lfuibyte\f1 and distinguish
it from \f4lfubyte\f1.
.LI
\f4fuword, fuiword, lfuword\f1
.br
These are analogous to previous byte routines, only these fetch words
from user space rather than bytes.
.LI
\f4subyte\f1
.br
This stores byte into user memory.
On separate ID machines this stores to user data space.
.LI
\f4suibyte\f1	
.br
This stores byte into user memory. 
On separate ID machines this stores to user instruction space.
.LI
\f4suword, suiword\f1
.br
These are analogous to \f4subyte\f1 and \f4suibyte\f1, 
only these store words rather than bytes into user space.
.LI
\f4memprobe\f1
.br
This checks validity of virtual address.
It returns 0 if memory is accessible and -1 if memory is inaccessible.
.LI
\f4spath\f1
.br
This reads a path name from kernel space.
It is called from \f4copystr\f1 (see \f3os/move.c\f1).
.LI
\f4upath\f1
.br
This reads a path name from user space.
It is called from \f4copyinstr\f1 (see \f3os/move.c\f1).
.LI
\f4kpath\f1
.br
This reads a path name from kernel space.
This routine is present for historical reasons.
.LI
\f4icode\f1
.br
This is an initial code for the \f4init\f1 process.
\f3main\f1 copies this code into user space at virtual address \f4UVTEXT\f1, 
and after \f3main\f1 returns to \f4vstart_s\f1,
\f4vstart_s\f1 does a \f4RETG\f1 to this code.
The code is initially executed in kernel mode, as it manipulates the process
control block pointer register (\f4pcbp\f1). 
It first sets up the stack, and then performs an \f4exec\f1 system call to run 
\f3/sbin/init\f1. 
\f2argv\f1 is the argument vector and \f2sbin_init\f1 contains the name of
\f3/sbin/init\f1.
.LI
\f4szicode\f1
.br
This is a global variable whose value is the length of the \f4icode\f1.
.LI
\f4searchdir\f1
.br
This searches a directory on an S5 type file system.
.LI
\f4is32b\f1
.br
This indicates the processor type, returning 0 if a processor is WE32001 and
1 if processor is WE32100.
.LI
\f4arglistsz\f1
.br
This computes size requirements of a process (\f2argc, argv\f1) style argument
list.
The comment in code is self-explanatory.
.LI
\f4copyarglist\f1
.br
This copies (\f2argc, argv\f1) style argument list.
Again, a comment in code is self-explanatory.
.LI
\f4userstrlen\f1
.br
This computes \f2strlen\f1 for string in user space.
It checks validity of user address, and will recover from faults in user space
using the \f4u_caddrflt\f1 mechanism.
.LI
\f4setintret\f1
.br
This loads a new return \f4pc\f1 into the PCB at the top of the interrupt
stack.
In C, the declaration is:
.DS
	\f4void setintret(pc)
	     void (*pc)();\f1
.DE
When the next \f4RETPS\f1 (or return from interrupt) occurs, and
the PCB is restored from the top of the stack, the process
will be running at the specified \f4pc\f1. 
This routine is used by \f4intsyserr\f1 (see \f3os/trap.c\f1) during
possible recovery from bus timeout interrupts.
.LE
.LI
\f3pstart.c  -  MD\f1
.BL
.LI
\f4pstart\f1
.br
This routine is part of the start-up sequence for the kernel.
It runs before virtual addressing has been enabled. 
Its primary responsibility is to set up the kernel memory map to be used in
virtual mode.
It also handles generating a crash dump, if necessary.
.LI
\f4mmusetup\f1
.br
This is used by \f4pstart\f1 to set up MMU.
.LE
.LI
\f3string.s\f1
.BL
.LI
\f4strcmp, strlen, strcpy\f1
.br
These are assembler versions of standard C routines.
.LE
.LI
\f3syms.s\f1
.br
This defines various system symbols, such as MMU or device register
offsets, as well as certain sections.
This file is needed for building the kernel with the ELF-based compilation system;
formerly, these symbols were defined in the COFF-based \f4ifile\f1.
.LI
\f3ttrap.s\f1
.BL
.LI
\f4int_null\f1
.br
This is a null interrupt handler.
It calls C routine \f4intnull\f1 (\f3os/trap.c\f1).
.LI
\f4swtch\f1
.br
This initiates context switch by switching to process control block 
\f4kpcb_pswtch\f1 (\f3ml/kpcbs.c\f1).
This transfers control to \f4ps_swtch\f1.
.LI
\f4callps\f1
.br
This switches control to specified process control block.
.LI
\f4ps_swtch\f1
.br
This saves current context pointer in u-area of the current process.
Then it calls \f4pswtch\f1 (see \f3disp/disp.c\f1) to do process switch and select
a possibly new process to run.
It then pushes context pointer of the new process onto the interrupt stack and 
branches to \f4int_ret\f1 to return to the new context.
.LI
\f4int_L9\f1
.br
This is a level 9 interrupt handler.
On the 3B2, the level 9 interrupt is processor-generated. 
The kernel generates a level 9 interrupt under any one of the following three
conditions, indicated by an associated flag:
.br
.sp
1. Power failure. 
The actual power failure generates a level 15 interrupt.
When the level 15 interrupt handler \f4intsyserr\f1 (\f3os/trap.c\f1) detects 
a power failure, it sets the flag \f2pwrflag\f1 and generates a level 9 interrupt.
The level 9 interrupt handler then takes actions to handle the power failure
gracefully.
.br
.sp
2. Uart/floppy timeout.
The integral uart driver provides a timeout-like facility to the integral
floppy driver.
When the timeout expires, the uart driver sets the flag \f2uartflag\f1
and generates a level 9 interrupt.
.br
.sp
3. Timeout/callout expiration.
When a timeout call has expired, the clock interrupt handler \f4clock\f1 
(\f3os/clock.c\f1) calls the routine \f4timepoke\f1 (\f3os/machdep.c\f1),
which sets the flag \f2timeflag\f1 and generates a level 9 interrupt.
.LI
\f4int_L15\f1
.br
This is a level 15 interrupt handler.
On the 3B2, the level 15 interrupt is triggered by the clock or a system error.
In the case of a clock interrupt, the interrupt handler calls \f4clock_int\f1
(\f3io/hrtimers.c\f1).
The return from \f4clock_int\f1 indicates whether or not profiling needs
to be done.
If profiling needs to be done, the system goes off
to execute the routine \f4addupc_clk\f1 (\f3os/trap.c\f1), but does so in
the context of the kernel PCB of the current process.
It does this by moving the address of the kernel PCB to the interrupt
stack to indicate that this is the interrupted PCB; then
storing the address of the \f4addupc_clk\f1 routine in the kernel PCB;
and finally executing a \f4RETPS\f1 to load the context specified by
the kernel PCB. 
\f4addupc_clk\f1 terminates by invoking \f4trap_ret\f1, 
the generic trap return routine.
.LI
\f4int_ret\f1
.br
This is a generic interrupt return sequence.
If the interrupt is returning to kernel mode, then a \f4RETPS\f1 instruction
is done to restore the interrupted context.
However, if the interrupt is returning to user mode, then the generic return
from trap sequence (\f4trap_ret\f1) is executed.
.LI
\f4trap_ret\f1
.br
This is a generic trap return sequence to return from kernel to user mode.
It schedules queue service routines if necessary, calls scheduling
class specific \f4trap_ret\f1 routine (i.e., the \f2cl_trapret\f1 field of the
class table entry for the scheduling class of the current process),
handles any last minute signal processing or preemption, and
returns to the user context.
.LI
\f4int_px\f1
.br
This handles 3B2 process exceptions.  
It calls \f4intpx\f1 (\f3os/trap.c\f1), which panics.
.LI
\f4int_sx\f1
.br
This handles 3B2 stack exceptions. 
If the exception occurred in kernel mode, this calls \f4intsxk\f1
(\f3os/trap.c\f1), which panics.
If the exception occurred in user mode, it calls \f4intsx\f1 (\f3os/trap.c\f1),
which tries to recover from the fault either by growing the stack
or paging it in.
If no recovery is possible, the process is sent a signal.
Pathological stack exceptions from user mode may cause a system panic.
.LI
\f4nrmx_ilc\f1
.br
This handles illegal level change exception.
This 3B2 exception occurs when a process tries to execute a \f4RETG\f1 
(return from gate) in which the privilege level of the saved \f4psw\f1 is
higher than the current privilege level.
This handler is used to preserve binary compatibility with signal handling
on previous UNIX System V releases on the 3B2.
.LI
\f4nrmx_iop\f1
.br
This is an illegal op-code handler used for old-style floating point
emulation. 
This is present for backwards compatibility with previous UNIX System V binaries.
.LI
\f4nrmx_XX\f1
.br
This handles normal exceptions.
It jumps to \f4nrmx_KK\f1 if exception occurred in kernel.
It calls \f4u_trap\f1 (\f3os/trap.c\f1) if exception occurred in user mode.
.LI
\f4nrmx_YY\f1
.br
This handles invalid system calls (i.e., \f4GATE\f1s) that are
treated as a normal exception.
.LI
\f4Xsyscall\f1
.br
This is a system call entry.
It calls \f4systrap\f1 (\f3os/trap.c\f1).
.LI
\f4nrmx_KK\f1
.br
This handles kernel exceptions. 
It calls \f4k_trap\f1 (\f3os/trap.c\f1) to try to recover.
If recovered, it returns.
If it didn't recover, it calls \f4krnlflt\f1 
(\f3os/trap.c\f1) which panics.
.LI
\f4rtnfirm\f1
.br
This returns to firmware on panics.
.LE
.LI
\f3uprt.s\f1
.BL
.LI
\f4pstart_s\f1
.br
This is the first code executed after boot.
This executes in physical memory mode.
This sets up the stack and calls \f3pstart.c\f1.
\f3pstart\f1 sets up the virtual memory mapping and then calls \f4pinset\f1.
.LI
\f4pinset\f1
.br
This is called from \f3pstart.c\f1 with a single argument, the page number of the
first free page.
This routine switches to virtual mode and calls \f4vstart_s\f1 (\f3ml/misc.s\f1). 
The \f4ENBVJMP\f1 instruction of the 3B2 enables virtual addressing and 
jumps to the address specified in \f4r0\f1.
The comments explain the arguments passed to \f4vstart_s\f1 and the
meaning of the autoconfiguration flag.
.LE
