Notes

advertisement
Xinu Programmer's Manual
Version 6b
(Xinu Is Not Unix)
June 1983
This manual contains a description of the
Xinu software. It has been divided into four sections. The introduction in section 0 describes
how to use the Xinu software to compile, download,
execute, and debug a C program.
Section 0 also
contains a set of informal implementation notes
that give the flavor of Xinu. Section 1 gives the
details and arguments of cross-development commands available on the host that cross-compile,
cross-assemble, cross-load, download, upload, and
analyze programs. Section 2 describes Xinu system
procedures that programs call to invoke operating
system services. Section 3 describes procedures
available from the standard libraries. From the
programmer's point of view, there is little distinction
between library routines and system
calls.
As in the UNIX manual, each page describes a
command, system call or library routine; section
numbers appear in the page header as "(digit)"
following the name of the program; within a section all pages are arranged in alphabetical order.
References have the same form as headers (e.g.,
"getc(2)" refers to the page for "getc" in section
2).
January 12, 1987
- 2 _ A _ S_ h_ o_ r_ t _ I_ n_ t_ r_ o_ d_ u_ c_ t_ i_ o_ n _ T_ o
_ X_ i_ n_ u _ a_ n_ d _ t_ h_ e _ C_ r_ o_ s_ s_ D_ e_ v_ e_ l_ o_ p_ m_ e_ n_ t _ S_ o_ f_ t_ w_ a_ r_ e
_ H_ o_ w _ t_ o _ U_ s_ e _ X_ i_ n_ u
_ A_ r_ c_ h_ i_ t_ e_ c_ t_ u_ r_ e.
Xinu comes in
a crossdevelopment environment that runs on the host machine (usually a Digital Equipment Corp. VAX), and an independent system that runs on the microcomputer (usually a Digital Equipment Corporation LSI 11/02). The microcomputer is connected
to the host over an asynchronous serial line like those used
to connect terminals. From the point of view of the host,
the microcomputer is simply another device that transmits
and receives characters; from the point of view of the
micro, the host is merely a console terminal that transmits
and receives characters.
two
parts:
_ O_ v_ e_ r_ v_ i_ e_ w. To run a program under Xinu, you create
the
source
file
on the host machine, and invoke crossdevelopment software to compile and load the program along
with the Xinu system. Once a complete memory image has been
produced, it can be downloaded onto the microcomputer where
it executes independent of the host. During execution, you
invoke a program on the host that captures characters emitted by the micro and displays them on the terminal screen,
and sends characters typed at the keyboard to the micro.
Thus, your terminal on the host appears to be connected
directly to the micro. If the micro crashes, it can be restarted without downloading (provided the crash did not destroy the program in memory). To help debug severe crashes,
the contents of memory on the micro can be uploaded to a
file on the host where a post-mortem program can analyze the
state and report problems.
_ C_ r_ o_ s_ s-_ D_ e_ v_ e_ l_ o_ p_ m_ e_ n_ t
_ c_ o_ m_ m_ a_ n_ d_ s. The cross-development system contains a C compiler, linking loader, downloader,
uploader, and post-mortem debugger as well as a few miscellaneous commands. The details can be found in section 1 of
this manual. These commands probably reside in the Xinu
"bin" directory on your system; the directory name must be
part of your PATH for you to execute them. If they are not
in directory /usr/Xinu/bin, consult whoever installed Xinu
to find out the bin directory name and add it to your path.
_ C_ o_ m_ p_ i_ l_ i_ n_ g _ p_ r_ o_ g_ r_ a_ m_ s. The command
_ c_ c_ 1_ 1 works like the
UNIX _ c_ c command.
It invokes the C cross-compiler, crossassember, and cross-loader to translate C programs into a
memory image.
Like _ c_ c, the actions of _ c_ c_ 1_ 1 depend on the
file names passed to it as arguments -- names ending in ".c"
are assumed to be C programs, those ending in ".s" are
assumed to be assember programs, and those ending in ".o"
are assumed to be previoulsy compiled object programs.
Unless you specify otherwise, _ c_ c_ 1_ 1 compiles C programs,
assembles assembler programs, and loads object programs to
Version 6b
produce a memory
image contains
program (you can
and just prepare
1/12/87
2
image in file _ a._ o_ u_ t. Normally, the
the Xinu operating system along with your
ask _ c_ c_ 1_ 1 to leave out the operating
a "stand-alone" program).
memory
system
_ D_ o_ w_ n_ l_ o_ a_ d_ i_ n_ g. Command _ d_ o_ w_ n_ l_ o_ a_ d
reads file _ a._ o_ u_ t, and
loads the memory image into the microcomputer (it will look
for the memory image in a different file if you instruct it
to do so).
Usually, _ d_ o_ w_ n_ l_ o_ a_ d is invoked with an
argument
"-a5" that causes the microcomputer to delay for five
seconds before starting execution of the downloaded program.
_ I_ n_ t_ e_ r_ a_ c_ t_ i_ n_ g _ w_ i_ t_ h _ t_ h_ e
_ M_ i_ c_ r_ o. The microcomputer on which
Xinu runs is attached to the host like a peripheral device.
The program _ o_ d_ t "connects" your terminal to the microcom-
puter by relaying characters between the terminal and the
device. Characters that arrive from the micro are sent to
your terminal, while characters typed on your keyboard are
sent to the micro. _ O_ d_ t can be invoked at any time, but it
is most often used just after a _ d_ o_ w_ n_ l_ o_ a_ d so you can see
the
output of the program as it runs. _ O_ d_ t will halt the microcomputer for you by "breaking" the console line if you type
the 2-character sequence backslash (\) followed by null
(CONTROL-@).
To proceed again, type uppercase-P (see the
LSI 11 manual for more information on the "odt" mode).
_ D_ e_ b_ u_ g_ g_ i_ n_ g _ a _ c_ r_ a_ s_ h. If the program
running on the micro
crashes, the cause of trouble may not be easy to spot. Help
is available from a post-mortem debugger, _ p_ m.
You must
first execute command _ u_ p_ l_ o_ a_ d to copy the complete memory
image from the micro into a file on the host.
By default,
the image file is named _ c_ o_ r_ e_ 1_ 1. After the
_ c_ o_ r_ e_ 1_ 1 file has
been created, run command _ p_ m to cull through it and print
out the system status.
_ P_ m uses both _ c_ o_ r_ e_ 1_ 1 and
_ a._ o_ u_ t to
diagnose the problem (as usual, the actual file names can be
changed if you don't happen to like them).
_ A_ n _ E_ x_ a_ m_ p_ l_ e
_ C_ r_ e_ a_ t_ e _ a _ C _ p_ r_ o_ g_ r_ a_ m. For example, here
is a C program
that prints the string "Hello world." on the console terminal and exits (_ P_ r_ i_ n_ t_ f is a system (library) procedure that
prints formatted strings on the console; other system commands are described in sections 2 and 3 of this manual):
/* example C program in file example.c */
main()
{
printf("Hello world.\n");
}
_ C_ o_ m_ p_ i_ l_ e _ a_ n_ d _ D_ o_ w_ n_ l_ o_ a_ d.
compile the program, download it onto the micro, and connect your terminal to the
Version 6b
1/12/87
1
Cross-
INTRO(0)
Xinu Programmer's Manual
INTRO(0)
micro with the following commands:
cc11 example.c
download -a5
odt
The cross-compiler will compile the C program, and load it
along with the Xinu system, leaving file _ a._ o_ u_ t in your
current directory. The downloader will copy the image from
_ a._ o_ u_ t into the micro and start it executing (after a delay
of five seconds). During downloading, you will see a count
of the bytes remaining as blocks are transferred. Finally,
_ o_ d_ t will connect your terminal to the micro (the 5-second
delay leaves time for the VAX to start _ o_ d_ t). When the micro
begins execution you will see a few Xinu system startup messages followed by the program output. When all of your
processes complete (in this case, when the single program
terminates), you will see a system termination message. The
output is:
Xinu Version 6.09b 3/1/83
57346 real mem
21268 avail mem
clock enabled
Hello world.
All user processes have completed.
_ R_ e-_ r_ u_ n _ t_ h_ e _ p_ r_ o_ g_ r_ a_ m.
program without
downloading the micro again, type:
To
re-run
the
\CONTROL-@
1000G
The 2-character sequence backslash (\) null (control-@)
causes _ o_ d_ t to halt the LSI 11 and place it in "ODT" mode.
The LSI 11 responds with an at-sign prompt.
The sequence
"1000G" starts the machine executing at location 1000
(octal). To get out of _ o_ d_ t, kill the process by typing the
"DELETE" key. Note that killing _ o_ d_ t does not stop the micro
-- it merely disconnects your terminal.
_ U_ p_ l_ o_ a_ d _ t_ h_ e _ m_ e_ m_ o_ r_ y. You may want to
see what processes
are (were) running.
To retrieve the memory image and
analyze it, run the commands:
upload
pm
Warning: _ u_ p_ l_ o_ a_ d destroys the contents of memory on the micro
as it executes, so the micro cannot be restarted again after
Version 6b
INTRO(0)
1/12/87
Xinu Programmer's Manual
2
INTRO(0)
uploading. Also note that if you interrupt (i.e. kill) the
uploader and then restart it, the image it retrieves will be
incorrect.
_ I_ n_ t_ e_ r_ p_ r_ e_ t_ i_ n_ g _ p_ m. _ P_ m reports things
like whether the
program text has been changed and the status of each process. If the output from _ p_ m seems unreasonable, check for
the following common errors. If significant portions of the
program have been changed, it may mean a stack overflow
occurred; totally meaningless process information often
indicate that the overflow extended into the process table.
Having only one or two bad process states in an otherwise
meaningful set may indicate that the context switch ended up
with no ready or current processes; this only happens if you
modify the system code or add your own device driver.
When
experimenting with device drivers, look carefully at the
status of the null process after a crash -- if you find it
sleeping, waiting, receiving, or suspended then you probably
have a lower-half driver routine that removes the null process from the current/ready lists.
_ S_ y_ s_ t_ e_ m _ T_ e_ r_ m_ i_ n_ a_ t_ i_ o_ n. Xinu may not
always print the system termination message even if all your processes exit,
because it interprets the term "user process" to mean "all
processes except the null process." This can be confusing
because the network software starts processes that never
terminate (they continue forwarding frames even if the CPU
is otherwise idle). Also remember that the tty driver will
continue to echo characters even if there are no processes
running to consume them.
_ H_ i_ n_ t_ s _ o_ n _ r_ e_ s_ t_ a_ r_ t_ i_ n_ g. The LSI 11
ODT command 1000G sets
the program counter to 1000 and starts execution with inter-
rupts _ e_ n_ a_ b_ l_ e_ d. Xinu disables interrupts immediately
after
it starts executing to avoid being interrupted before the
system is ready. If an interrupt occurs before the LSI 11
can execute the first instructon, it may cause the system to
crash (ungracefully). If your processor gives you trouble
with the "G" command, then type the following three lines to
restart Xinu:
RS/xxxxxx 340
R7/xxxxxx 1000
P
The LSI 11 will print octal values in place of xxxxxx.
Note: no carriage return is used after the "P" command (consult the LSI 11 manual for more information).
Version 6b
3
_ X_ i_ n_ u _ I_ m_ p_ l_ e_ m_ e_ n_ t_ a_ t_ i_ o_ n
_ N_ o_ t_ e_ s
Updated 1/82, 3/82, 11/82.
These are the notes kept during implementation; they
are not designed as an accurate introduction to Xinu. In
particular, deferred operations implemented with _ p_ m_ a_ r_ k
disappeared from the book version even though they remain in
version 5.
Some quick ideas:
-
There are multiple processes.
-
A process is known by its process id.
-
The process id is an index into the process table.
-
There are counting semaphores.
have
-
A semaphore is known by its index in the semaphore table.
-
There is a line time clock.
-
The system schedules processes based on priority.
-
The system supports I/O.
-
For tty I/O characters are queued on input and output.
The normal mode includes echoing, erasing backspace, etc.
-
There is a frame-level data link
to make a ring of LSI 11's.
-
There is a file system that supports concurrent growth of
files without preallocation; it has only a single-level
directory sturcture.
-
There is a one-word message passing mechanism.
-
There is support for self-initializing routines (memory
marking) that makes the system serially reusable without
requiring the kernel to explicitly call initialization
routines.
-
Processes can create processes, kill processes, suspend
processes, restart processes, and change the priority of
processes.
-
There is no real memory management, but there are primitives for acquiring and returning memory from the global
pool, and a way to suballocate smaller pools of fixedsize buffers.
-
There is a configuration program, config, to
Version 6b
NOTES(0)
communications
package
generate
1/12/87
Xinu Programmer's Manual
a
1
NOTES(0)
Xinu system according to specifications given.
Discussion of implementation:
0. Files. The system sources are organized as a set of procedures.
For the most part, there is a file for each
system call (e.g., chprio.c for the system call chprio).
In addition to the system call procedures, a file may
contain utility functions needed by that system call.
Files which do not correspond to system calls are:
Configuration
The file of device and constant information as edited
by the user to describe the hardware; the config program takes this file and produces conf.c and conf.h
files.
conf.h
Generated constants including I/O and size
do not edit directly.
conf.c
Generated file of initialized variables; do
directly.
constants;
not
edit
kernel.h
General symbolic constants; misc defined macros.
proc.h
Process table entry structure declaration; state
stants.
con-
sem.h
Semaphore table entry structure declaration; semaphore
constants.
io.hGeneral user-level I/O definitions.
slu.h
Serial Line Unit CSR layout; I/O constants for slu's.
tty.h
tty line discipline control block, buffers,
sizes.
excluding
dlc.h
line discipline control block for asynchronous
used as network interface.
device
disk.h
disk driver control block.
Version 6b
1/12/87
2
NOTES(0)
Xinu Programmer's Manual
NOTES(0)
dtc.h
Digital Technology Corp. SASI disk interface
register layouts.
hardware
xebec.h
Xebec Corp. SASI disk controller register layouts.
frame.h
Xinu ring network frame format definitions.
bufpool.h
Buffer pool constants and format.
mark.h
Memory marking table declarations.
mem.h
Memory management free list format declarations.
ports.h
Definitions for communications ports (queued interprocess rendevous points).
sleep.h
Definitions for real-time delay software.
dir.h
Layout of disk directory block.
iblock.h"
Layout of index block (i-block).
file.h
Definitions of variables and
local file system routines.
constants
used
by
the
q.hq data structure declaration (see below); defined macros for q predicates.
queue.c
q manipulation routines.
resched.c
Almost the inner most routine (rescheduler).
It
selects the next process to run from the ready queue
and fixes up the state. Calls ctxsw to switch contexts.
cxtsw.s
The routine that actually changes the executing process into another one. A very small piece of assembler code with only one trick: when a process is
saved, the execution address at which it restarts is
actually the instruction following the call to ctxsw.
Version 6b
NOTES(0)
1/12/87
Xinu Programmer's Manual
3
NOTES(0)
lowcore.s
The loaded version of the low part of memory (interrupt vectors). All interrupt vectors are initialized
by the loader to point to panic routines,
and
overwritten for valid devices at startup.
ioint.s
I/O interrupt dispatchers.
startup.s
Actual entry point (start) with code to set up C runtime environment and call high-level initialization.
initialize.c
All external (global) variables, the null process
(process 0, see below), and the high-level system initialization routine (e.g., to craft the process table
entry for process 0).
userret.c
The routine to which user processes return (i.e. exit)
if they ever do. Care should be taken so that userret
never exits; it must kill the process that runs it
because there is no legal return frame on the stack.
sizmem.s
Utility procedure to size main memory.
1. Process states. Each process has a state given by the
pstate field in the process table entry. The state
values are given by symbolic constants PRxxxx.
PRFREE
means that the process entry is unused. PRREADY means
that the process is linked into the ready list and is
eligible for the CPU. PRWAIT means that the process is
waiting on a semaphore (given by psem).
PRSUSP means
that the process is in hibernation; it is not on any
list. PRSLEEP means that the process is in the queue of
sleeping processes waiting to be awakened. PRCURR means
that the process is (the only one) currently running.
The currently running process is NOT on the ready list.
In addition to the actual state, there is a "mark" field
(pmark) which indicates pending state changes. PMDEAD
indicates that the process has been killed and should be
removed as soon as it reaches the ready queue. PMSUSP
indicates that the process has been suspended and should
move to the suspended state as soon as it reaches the
ready queue. PMNONE indicates no pending action.
2. Semaphores. Semaphores reside in the array semaph. Each
entry in the array corresponds to a semaphore and has a
count (scount), and state (sstate). The state is SFREE
if the semaphore slot is unassigned, SUSED if the
Version 6b
NOTES(0)
1/12/87
Xinu Programmer's Manual
4
NOTES(0)
semaphore is in use. If the count is -p then the sqhead
and sqtail fields point to a FIFO queue of p processes
waiting for the semaphore. If the count is nonnegative p
then no processes are waiting. More about the head and
tail pointers below.
3. Suspension. Suspended processes are forbidden from using
the CPU. They may remain on semaphore/sleep queues until
they are to be moved to the ready queue.
A call to
ready(p), where p has been marked suspended, will NOT
place it on the ready queue. It will merely result in p
being placed in the suspended state. Suspending a process that is already on the ready queue will remove it.
Suspending the current processes forces it to give up the
CPU.
4. Sleeping. When a process calls sleep(n) it will be
delayed n seconds. This is achieved by placing the process on a queue of jobs ordered by wakeup time and relinquishing the CPU.
Every 60th of a second, an external
line-time clock will interrupt the CPU and cause a clock
interrupt routine to be called. To avoid extra overhead,
5 such interrupts are ignored before one is processed.
Thus, the granularity of clock counts is 1/10 of a
second. The interrupt handler maintains a clock and
moves processes back to the ready queue when their wakeup
time has been reached. Notice that a process may put
itself, but no one else, to sleep.
5. Queues and ordered lists. There is one data structure
for all heads, tails, and elements of queues or lists of
processes: q[]. The first NPROC entries in q (0 to
NPROC-1) correspond to the NPROC processes. If one wants
to link process i onto a queue or list, then one uses
q[i].qnext and q[i].qprev as the forward and backward
pointers.
The remaining entries in q are used for the heads and
tails of lists. The integer nextqueue always points to
the next available entry in q to assign. When initialize
builds the heads and tails of various lists, it assigns
entries in q sequentially. Thus, the sqhead and sqtail
fields of a semaphore are really the indices of the head
and tail of the list in q. The advantage of keeping all
heads and tails in the same data structure is that
enqueueing, dequeuing, testing for empty/nonempty, and
removing from the middle (eg., when a process is killed)
are all handled by a small set of simple procedures
(files queue.c and q.h). An empty queue has the head and
tail pointing to each other. Since all real items have
index less than NPROC, testing whether a list is empty
becomes trivial. In addition to FIFO queues, q also contains ordered lists based on an integer kept in the qkey
field. For example, processes are inserted in the ready
Version 6b
NOTES(0)
1/12/87
Xinu Programmer's Manual
5
NOTES(0)
list (head at position q[rdylist]) based on their priority. They are inserted in the sleep list based on wakeup
time.
Ordered lists are always in ascending order with
the inserted item stuck in BEFORE those with an equal
key.
Thus, processes are removed from the ready list
from the tail to get the highest priority process. Also,
processes of equal priority are scheduled round robin.
Since the sleep queues are serviced from the smallest to
largest keys, items are removed from the head of the
queue (equal keys do not matter for sleeps).
6. Process 0. Process 0 is a null process that is always
available to run or is running. Care must be taken so
that process 0 never executes code that could cause its
suspension (e.g. it cannot wait for a semaphore). Since
Process 0 may be running during interrupts, this means
that interrupt code may never wait for a semaphore. Process 0 initializes the system, creates the first user
process, starts it executing the main program, and goes
into an infinite loop waiting until an
interrupt.
Because its priority is lower than that of any other process, the null process loop executes only when no other
process is ready.
It uses a pause instruction while
waiting to avoid taking bus cycles just in case dma devices are running.
Version 6b
1/12/87
6
Download