[net.sources] bootblk - PDP-11 reboot program

ecn-pa:bruner (12/15/82)

Here is a program that I wrote for performing reboots on a PDP-11.
It uses the "phys" system call to gain access to the I/O page,
copies a block from a specified file to location zero, and starts
the processor in kernel mode at zero.  The program is called
"/etc/bootblk" (deliberately difficult to type) and is used for
software-directed reboots (our "init" program performs system shutdowns
and reboots when sent appropriate signals from a "shutdown" program,
for example).

This runs on V7, but I see no reason why it won't work on 2.8 BSD
as well (if you change BSIZE to 1024.)  No flames, please -- I know
this is "dirty".  I offer only the following skimpy defense:

    It works.

    It is only done (at most) once per instance of the kernel.

    Rebooting is inherently machine-dependent anyway.

--John Bruner

------------------------------------------------------------------------
.TH BOOTBLK 8
.SH NAME
bootblk  \- reboot PDP\-11 using specified block
.SH SYNOPSIS
.B bootblk
file
.SH DESCRIPTION
The PDP\-11 hardware bootstrap facility
loads a block from a specified device
into low physical memory
and transfers control to it.
.I Bootblk
accomplishes these functions in software.
.I Bootblk
requires exactly one argument \(em
the name of the file containing
the bootstrap block.
This may be an ordinary file,
block device,
or character device.
The first 512 bytes of the file
are copied into low physical memory
and executed.
.PP
No special action
(e.g.
.IR sync )
is performed
before the system is rebooted.
This permits
.I bootblk
to be used during automatic filesystem
recovery when it is desirable to reboot
without a
.I sync
after fixing problems on the root filesystem.
Thus,
.I bootblk
should rarely
(if ever)
be used directly by a human operator.
Instead,
the `\-r'
option of the
.I shutdown
program should be used to provide
a controlled system shutdown/reboot.
.PP
.I Bootblk
uses the
.I phys
system call to obtain access to the hardware
device registers.
Since the
.I phys
system call is only permitted for the super-user,
.I bootblk
can only be run by the super-user.
.SH DIAGNOSTICS
Error messages are self-explanatory.
If an error occurs,
the error message will be printed
and
.I bootblk
will exit with low physical memory unchanged.
If no error occurs,
the system will reboot.
.SH SEE ALSO
fsck (1),
phys (2),
sync (2),
init (8),
shutdown (8)
.SH BUGS
If a power-fail occurs while
low memory is being set up,
unpredictable things will occur.
This problem is unavoidable.
------------------------------------------------------------------------
/
/	bootblk file
/
/	Do NOT load as shared text or separated I/D; assemble with:
/
/	as -o /etc/bootblk /usr/include/sys.s bootblk.s
/

BSIZE = 512.

SEG = 6
SEGSIZE = 8192.
SEGS64 = SEGSIZE\/64.
SEGOFF = -SEGSIZE
DEVADR = 177600

PS = 177776
UIPAR0 = 177640
UDPAR0 = 177660

BR7 = 340

SETKERN = 10415			/ mov r4,(r5)
RESET = 5			/ reset
CLRPC = 5007			/ clr pc


	mov	$synerr,r4	/ get boot filename
	mov	4(sp),fname
	beq	error		/ if none, abort
	mov	$ioerr,r4	/ open file and read one block
	sys	open; fname:0; 0
	bes	error		/ open error, abort
	sys	read; buf; BSIZE
	bes	error		/ read error, abort
	mov	$physerr,r4	/ map device regs into user space
	sys	phys; SEG; SEGS64; DEVADR
	bes	error

	mov	$buf,r0		/ r0 = index into buffer (just read)
	clr	r1		/ r1 = index into memory page zero
	mov	$BSIZE,r2	/ r2 = limit (one buffer) in page zero
	mov	$BR7,r4		/ r4 = PSW bits for CPU priority 7
	mov	$PS+SEGOFF,r5	/ r5 = accessible PSW address
	jmp	copy		/ go to the next segmentation register

error:
	mov	r4,r3		/ r4 = address of error message
1:
	tstb	(r3)+		/ look for end of string (null byte)
	bne	1b
	sub	r4,r3		/ r3 = length of message
	dec	r3		/ (no need to print null)
	mov	r4,errbuf
	mov	r3,errlen
	mov	$2,r0		/ output on standard error
	sys	write; errbuf:0; errlen:0
	mov	$1,r0		/ exit with error status
	sys	exit

synerr:	<Syntax is "reboot filename"\n\0>
ioerr:	<i/o error\n\0>
physerr:<"phys" system call failed\n\0>

. = SEGSIZE^.

/	Finally, the buffer that was just read in is copied to
/	physical memory starting at location zero.  This is done
/	directly by changing the ua0 (first user-mode segmentation
/	register) to point to zero.  After copying in the buffer,
/	three instructions are written to change the processor
/	to kernel mode and start at location zero with memory
/	management off:
/
/		mov	r4,(r5)		/ set kernel mode, priority 7
/		reset			/ bus init
/		clr	pc		/ start bootstrap at zero
/

copy:
	bis	r4,(r5)		/ spl7
	mov	r1,*$UIPAR0+SEGOFF	/ (r1 = 0)
	mov	r1,*$UDPAR0+SEGOFF

/	There is no turning back now.

2:
	mov	(r0)+,(r1)+	/ copy in the bootstrap block
	cmp	r1,r2
	blo	2b
	mov	$SETKERN,(r1)+	/ set up for the restart
	mov	$RESET,(r1)+
	mov	$CLRPC,(r1)+
	jmp	(r2)		/ reboot

.bss
buf:	.=.+BSIZE
------------------------------------------------------------------------
<end-of-information>