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>