AUTOMATIC BOOTSTRAP FOR THE VAX

by Alex Wong
Singapore Computer Systems
VAX PROFESSIONAL, JUNE 1987


There are many occasions when I wish the SHUTDOWN option "When will the system be rebooted" would do its job truthfully by booting the VAX up at the time I innocently entered. SHUTDOWN will even tell everyone on the system that it will be "back up 12-MAY-1986 8:00" and on that day, if you are late, you and your future generations will be branded as thieves and liars. There is no VMS facility to automatically boot the system up at a specific date and time and this can be quite useful.

Our VAX 11/730 is brought down every evening and weekend to avoid power failure problems and since we do not need to operate non-stop, a UPS is not justified. This means that every morning, someone has to turn on the system and wait for the date and time prompt before making the first coffee of the day. Even if you don't need coffee, the TU58 taking its own sweet time to load microcode can make you take valium instead. With a self-boot facility, you can solve the inconvenience of the daily startup chores and have a peaceful night's sleep as well.

The idea of an automatic startup is to accept the reboot time during SHUTDOWN, convert it to an appropriate format and write this into a specific memory location. The last program that SHUTDOWN invokes is OPCCRASH which does some housekeeping work before bugchecking the processor. OPCCRASH can be patched to read the reboot time from memory, compare it with the VAX internal clock and loop until both are equal. The processor can then be rebooted by writing F02 (hex) to the console transmit data buffer register (PR$_TXDB).

The VAX has a time-of-day clock which is accessible through a 32-bit internal register PR$_TODR and is constantly updated by hardware every 10 milliseconds. Battery backup for the clock is not a standard feature on the 11/730, hence the need to enter the date and time at startup. The base time for the time- of-day clock is 00:00:00.00 hours on January first of the current year. Basically, this means PR$_TODR contains the number of 10-ms intervals that have elapsed since 1-JAN-YYYY 00:00:00. This figure is biased by 10000000 (hex) so that smaller values would indicate loss of power or register overflow, requiring the operator to reset the time.

System time, however, is defined by a 64-bit value measuring the number of 100-nanosecond intervals since 00:00 hours November 17 1858, the time base for the Smithsonian Institution astronomical calendar. The timer and time conversion system services such as BINTIM or ASCTIM accept system time in the dd-mmm-yyy hh:mm:ss format and produce a quadword result. You can see from this that the system time must be converted to a 32-bit TODR format for time comparison.

The VMS system management procedure SHUTDOWN.COM brings down the operating system in an orderly manner so that the processor can be powered off. As a friendly gesture, it will prompt you for "When will the system be rebooted" but do nothing apart from promising the world that it will be "back up later". The answer to the prompt is stored in an imaginatively-named symbol called ANS which is accessible by a program called AUTOBOOT. This program checks ANS for either a null (produced by a carriage return response) or a valid system time. If response is invalid, a local symbol OK is set to "0" which causes SHUTDOWN to reprompt for reboot time. SHUTDOWN has been modified to include this check and the changes are shown below.

ORIGINAL:
        $a10: read/end_of_file=a10/prompt="''p3'" sys$command ans
        $if ans .eqs. "" then ans = p4
CHANGED TO:
        $a10: read/end_of_file=a10/prompt="''p3'" sys$command ans
        $ IF F$LOCATE("system be rebooted",P3) .EQ. F$LENGTH(P3) THEN GOTO CONTIN
        $ RUN SYS$SYSTEM:AUTOBOOT
        $ IF .NOT. OK THEN GOTO A10
        $ CONTIN:
        $if ans .eqs. "" then ans = p4
The F$LOCATE(...) test is necessary because SHUTDOWN works in a recursive manner. For each shutdown option, SHUTDOWN will invoke itself with several parameters, one of which is the prompt to be displayed. Since the above portion of DCL code is common to all options, the test ensures that the AUTOBOOT program will be activated only in response to the prompt for reboot time.

AUTOBOOT converts a valid system time from its character form in ANS to a quadword value by calling the BINTIM system service. To obtain the reboot time in 32-bit TODR form, the system time for 1-JAN-YYYY 00:00:00 is subtracted from it and divided by 100000, giving the number of 10-ms intervals since the start of year. This figure is written into memory location SYS$GQ_VERSION which holds the VMS version number "V4.3". On my system, it is at 80002BF4 and can be verified by checking SYS.MAP or use ANALYZE/SYSTEM and invoke the command SHOW SYMBOL SYS$GQ_VERSION. You can, of course, use any other "safe" locations if you like. For a null response, a zero longword is written to memory. Incidentally, SHUTDOWN requires CMKRNL privilege to run so there is no problem for AUTOBOOT to zap protected memory.

OPCCRASH executes in kernel mode to perform tasks such as flushing out the modified page cache before bugchecking the processor. The image can be patched to include code to extract the reboot time and do time comparisons at the point just before the bugcheck code. To determine the patch address, analyze the image OPCCRASH.EXE in SYS$SYSTEM to get the first transfer address.
        $ ANALYZE/IMAGE SYS$SYSTEM:OPCCRASH
                   :
          Image Activation Information
        
            first transfer address:  %X'00000292'
            second transfer address: %X'00000000'
            third transfer address:  %X'00000000'
                   :
Add 2 to it (for the entry mask) and use PATCH to examine the instructions until you encounter the location of instruction MTPR B^36E,#12 (366 in my case).
        $ PATCH
        PATCH> E/I 294
              :
        PATCH> E/I
              :
This instruction raises the IPL to lock out all interrupts before the bugcheck. To be safe, confirm this by reading the VMS microfiche on OPCCRASH. Below is a patch procedure OPPATCH.COM that I've used on my system to insert the extra code. The patch procedure is invoked by the DCL command "$ PATCH @OPPATCH".
        OPCCRASH.EXE
        INSE/I 366='MTPR B^0000036E,#12'
        'MOVL @#^X80002BF4,R9'
        'TSTL R9'
        'BEQL FIN'
        'LOOP: MFPR #^X1B,R8'
        'CMPL R8,R9'
        'BLSSU LOOP'
        'MTPR #^XF02,#^X23'
        'FIN: NOP'
        EXIT
        UPDATE
The startup time is placed in R9 and tested for zero. If non-zero, the code loops around comparing R8 (PR$_TODR) with the R9 until both are equal. The processor is then rebooted by setting PR$_TXDB to ^XF02. If a zero is extracted, code returns and OPCCRASH will bugcheck the processor as per normal. The TODR(1B) and TXDB(23) internal registers are described by the VAX Hardware Handbook and the Architecture Handbook.

Copy AUTOBOOT into SYS$SYSTEM and make sure you have duplicates of SHUTDOWN and OPCCRASH before patching them. Below is a system shutdown with reboot at 8:00 am the next day (10-MAY-1986).
        $ @SYS$SYSTEM:SHUTDOWN
        
                SHUTDOWN -- Perform an Orderly System Shutdown
        
        How many minutes until final shutdown [0]:
        Reason for shutdown [Standalone]:
        Do you want to spin down the disk volume [NO]? YES
        Do you want to invoke the site-specific shutdown procedure [YES]?
        Should an automatic system reboot be performed [NO]?
        When will the system be rebooted [later]: 10-MAY-1986 8:00
                                  :
Apart from the time, the only other valid entry is a carriage return. After performing the shutdown functions, the CPU will monitor TODR until wakeup time. The VMS 4.2 Release Notes states that the TODR register may not be common to all VAX processors and recommends the use of a TIMEDWAIT macro in LIB.MLB, so check this out. On my 11/730, there were no problems in accessing TODR directly. Remember to put back the original SHUTDOWN and OPCCRASH before doing any VMS update as the update may patch them.
          .TITLE  AUTOBOOT
        ; *******************************************************************
        ; AUTOBOOT: SHUTDOWN.COM PROMPTS FOR THE REBOOT TIME WHICH IS PLACED
        ; IN LOCAL SYMBOL "ANS". AUTOBOOT CHECKS ANS FOR NULL [later] OR A
        ; VALID SYSTEM TIME. AN INVALID RESPONSE WILL SET LOCAL SYMBOL "OK"
        ; TO ERROR (0) WHICH CAUSES SHUTDOWN TO REPROMPT FOR TIME. IF NULL,
        ; ZERO IS WRITTEN INTO LOCATION SYS$GQ_VERSION. IF VALID SYSTEM TIME,
        ; CONVERT IT TO MILLISEC BEFORE WRITING TO MEMORY.
        ;
        ; AUTHOR: ALEX WONG, SYSTEMS MANAGER    CPU : 730, VMS 4.3
        ;         SINGAPORE COMPUTER SYSTEMS
        ; GEN   : MACRO AUTOBOOT, LINK AUTOBOOT   DATE: 8-MAY-1986
        ; *******************************************************************
          $LIBCLIDEF                  ; CLI DEFS
          VERSION=^X80002BF4          ; LOC SYS$GQ_VERSION
        ;                             
        LOCSYM: .BLKL 1               ; DCL SYMBOL TABLE
        STIM: .BLKQ 1                 ; DAY1 IN NANOSEC
        ETIM: .BLKQ 1                 ; REBOOT TIME (NS)
        PARM: .LONG 1                 ; CMKRNL ARG LIST
          .ADDRESS  TIMEUP            
        TIMEUP: .BLKL 1               ; REBOOT TIME (MS)
        GPDESC: .LONG 50              ; COMMON STRING DESC
          .ADDRESS  BUF               
        BUF:  .BLKB 50                
        UPDESC: .LONG 50              ; UPCASE STRING DESC
          .ADDRESS  UPBUF             
        UPBUF:  .BLKB 50              
        ERSTAT: .LONG 1               ; ERROR STATUS DESC
          .ADDRESS  STAT              
        STAT: .ASCII  /0/             ; INIT TO ERROR
        DAY1: .LONG 23                ; START OF CURR YEAR
          .ADDRESS  ATIME
        ATIME:  .ASCII  /01-JAN-YYYY 00:00:00.00/
        ANS:  .ASCID  /ANS/           ; DCL SYMB ANS
        OK: .ASCID  /OK/              ; DCL SYMB OK
        
        ;
          .ENTRY  AUTOBOOT,^M<>
        ;
          CLRL  TIMEUP                ; INIT TO ZERO
          MOVL  #LIB$K_CLI_LOCAL_SYM,LOCSYM ; LOC SYMB TABLE
          $GETTIM_S   TIMADR=STIM     ; CURR DATE+TIME (NS)
          $ASCTIM_S   TIMBUF=GPDESC,TIMADR=STIM ; CONV TO ASCII
          MOVL  BUF+7,ATIME+7         ; EXTRACT CURR YEAR
          $BINTIM_S   TIMBUF=DAY1,TIMADR=STIM ; DAY1 IN NANOSEC
          PUSHAW  GPDESC              ; SET UP CALL
          PUSHAQ  GPDESC
          PUSHAQ  ANS
          CALLS #3,G^LIB$GET_SYMBOL   ; READ ANS
          BLBC  R0,FIN
          TSTW  GPDESC                ; IS IT NULL ?
          BEQL  DEFAULT               ; YES, SET ZERO
          MOVW  GPDESC,UPDESC         ; NO, SET UP CALL
          PUSHAQ  GPDESC
          PUSHAQ  UPDESC
          CALLS #2,G^STR$UPCASE       ; CONV TO UPCASE
          $BINTIM_S   TIMBUF=UPDESC,TIMADR=ETIM ; NANOSEC SYS TIME
          BLBC  R0,FIN
          MOVQ  STIM,R9               ; SET UP 64-BIT SUB
          MOVQ  ETIM,R7
          SUBL2 R9,R7                 ; SUB LOW 4 BYTES
          SBWC  R10,R8                ; SUB HIGH 4 BYTES
          EDIV  #100000,R7,R7,R8      ; CONV TO MILLSEC
          ADDL3 #^X10000000,R7,TIMEUP ; ADD CLOCK BIAS
        DEFAULT:
          $CMKRNL_S   ROUTIN=PUTIME,ARGLST=PARM ; ZAP PRIV MEMORY
          MOVB  #^A/1/,STAT           ; SET SUCCESS
        FIN:                          
          PUSHAL  LOCSYM              ; LOC SYMB TABLE
          PUSHAQ  ERSTAT              ; STATUS
          PUSHAQ  OK                  ; DCL SYMBOL OK
          CALLS #3,G^LIB$SET_SYMBOL   ; SET SYMBOL
          RET                         
        ;                             
          .ENTRY  PUTIME,^M<>         
          MOVL  @B^4(AP),@#VERSION    ; ZAP LOCATION
          MOVL  #1,R0                 ; SET SUCCESS
          RET
          .END  AUTOBOOT