Feedback Search Top Backward Forward

Rebooting OS/2

Written by Roman Stangl




OS/2 may be rebooted by using the SETBOOT utility, that is shipped with OS/2. However when adding a reboot feature in your application you may want to avoid the effort starting another session, as you can easily do the same yourself.

Using the DOS.SYS device driver

You can easily implement the way SETBOOT works, you just need to open the device DOS$ and make an IOCTL-call, however this call is undocumented. Both, the following code using DOS$ and SETBOOT, require that the device driver DOS.SYS is included in your CONFIG.SYS (as you can only get access to the reboot-vector from ring-3 by a device driver, and DOS.SYS provides that functionality).

If you have not installed the device driver DOS.SYS (which for example the IBM EWS BOOTOS2 package doesn't), add it to your CONFIG.SYS (where d: is your boot drive):

  • For OS/2 2.11 and before add the line DEVICE=d:\OS2\DOS.SYS.
  • For OS/2 Warp add the line DEVICE=d:\OS2\BOOT\DOS.SYS.
Now you should be able to add a reboot function by a few additions to your code. To access the device driver DOS.SYS you have to open the device DOS$ as shown in Figure 2.1.a. You want to check the return code, as you should inform the user or write a log, if the device couldn't be opened.

  apiretDosDD=DosOpen("\\DEV\\DOS$", &hfileDosDD, &ulAction, 0,
      OPEN_ACCESS_READWRITE, 0); if(apiretDosDD!=NO_ERROR)
Figure 2.1.a

Once you have opened the DOS$ device, you might inform the user that a ShutDown is in progress and finally shut down the file system by calling the API DosShutdown(). DosShutdown() will not stop processes from running, but file system calls will no longer work (therefore we had to open the device DOS$ before, as DosOpen is a file system call). Not having tested it, I would say threads making file system calls will either simply block or fail. Figure 2.1.b shows the call to DosShutdown(), though its quite well documented in the online reference.

/* Shutdown the system anyway */
Figure 2.1.b

Having shut down OS/2, you might again inform the user what's going on. You can do this for example by updating a text in a message box, just ensure that this text is already loaded into memory (and hope that is hasn't been paged out of memory, but this is very very unlikely, I personally have never experienced such a problem).

You jump to the reboot vector by calling a function of the DOS$ device as shown in Figure 2.1.c.

                           NULL)) ...
Figure 2.1.c

Last but not least, Figure 2.1.d shows the parameters for the undocumented interface of the DOS$ device to call the reboot vector,

  #define IOCTL_DOS                   0x00D5
  #define DOS_REBOOT                  0x00AB
Figure 2.1.d

In case something didn't work you also want to close the DOS$ device, and inform the user.

Using IOPL segments

Every workstation can also be rebooted by programming the keyboard controller and for at least MicroChannel PC's also by using the system control port A. The programming requires I/O and therefore must be done from a ring-2 IOPL segment (unless you are using the advanced methods to access I/Os, that is device drivers, call gates or ring-3 IOPL segments which have been described in other issues of EDM/2. I strongly discourage using this approach, because for me it didn't work reliably (e.g. ThinkPads seem to ignore this completely, most likely due to some power management hardware, I know that the code is processed for sure because I traced processing to the I/O instructions with the kernel debugger) and IOPL segments are non portable 16 bit code that is likely to be unsupported in the future.

Anyway, implementing it I found the solution of some interesting problems, so I've included it here too.

Let's start by a short look into Figure 3.1.a which shows the assembler code to reboot a workstation by trying to force activation of the reset line:

  1. First, reset is tried via the system control port A. This will likely work only on MicroChannel machines, but on such machines it would be the fastest method, much faster then using the keyboard controller. This is an example of superior technology introduced with the MicroChannel architecture, which unfortunately has been killed by IBM's inability to market such advantages.
  2. If reset via the system control port A didn't work, system reset is tried via the keyboard controller. One doesn't know if the first method worked, but if it worked execution is stopped by the hardware reset anyway.
Note: Though OS/2 code is presented here, it's quite easy to assemble a DOS version, by changing Assembler switches.

  ;*                              PC2.c
  ;*         Copyright (C) by Stangl Roman, 1993, 1994, 1995
  ;* This Code may be freely distributed, provided the Copyright isn't
  ;* removed, under the conditions indicated in the documentation.
  ;* Reboot.asm   IOPL segment to reboot OS/2 by trying to hardware
  ;*              reset the system by system control port A and by
  ;*              programming a keyboard controller reset.
  ;*              Unfortunately this does not work always, e.g. doesn't
  ;*              work on a IBM ThinkPad 701, doesn't work reliably on
  ;*              a PS/2 77i but perfectly works on a IBM PC 750. I
  ;*              think this is due to a hardware incompatibility to
  ;*              support features as APM (Advanced Power Management)
  ;* Use the function prototype:
  ;* extern USHORT _Far16 _Pascal RebootSystem(USHORT usPerformReset);
  ;* Add to your module definition file:
  ;*             RebootSystem=REBOOTSYSTEM   1


          db      "@(#) $Header: Reboot.asm Version 2.00 05,1995 $ (LBL)"

  ; MACRO to let the processor loop after IN, OUT instructions
      Local   IOW_Loop
          JMP     $+2
          PUSH    CX
          MOV     CX,010h
          LOOP    IOW_Loop
          POP     CX

    ; System control port A (see PS/2 technical references)
  CONTROLPORTA            EQU 092h
    ; AND mask to toggle reset bit (bit 0) of control port A off
  RESETOFF                EQU 0FEh
    ; OR mask to toggle reset bit (bit 0) of control port A on
  RESETON                 EQU 001h

    ; Keyboard controller status port (reading)
  KBDSTATUS               EQU 064h
    ; Input buffer full
    ; Keyboard command pulse output port

  Stackframe      struc      ; Structure for arguments passed on stack
                  dw      0h       ;   BP+00 : Saved BP
                  dw      0h       ;   BP+02 : IP of return address
                  dw      0h       ;   BP+04 : CS of return address
          arg1    dw      0h       ;   BP+06 : First parameter passed
          arg2    dw      0h       ;   BP+08 : Second parameter passed
  Stackframe      ends

  ;* This function programs the system control port A and the keyboard
  ;* controller to reset the system via activation the reset line (both
  ;* ways are used to increase the probability it works). This function
  ;* must be in an segment having IOPL privileges because the control
  ;* port A and the keyboard controller is programmed via I/O
  ;* instructions.

  PUBLIC  REBOOTSYSTEM     ; USHORT RebootSystem(USHORT argument 1)
          PUSH    BP
          MOV     BP, SP
          MOV     AX, Stackframe.arg1[BP] ; Access argument 1
          XOR     AX, 0FFFFh              ; Return failure
          CMP     AX, 0FFFFh
            ; ? If argument 1 is FALSE return with failure
            ;   to allow caller to call our code for diagnostics
          JE      RS_Return

          IN      AL, CONTROLPORTA      ; Get system control port A
          MOV     CX, 01000h              ; Retry counter
          AND     AL, RESETOFF  ; Toggle reset bit 0 off, on and off
          OUT     CONTROLPORTA, AL
          OR      AL, RESETON
          OUT     CONTROLPORTA, AL
          AND     AL, RESETOFF
          OUT     CONTROLPORTA, AL
          LOOP    RS_SystemReset          ; Try a few times

          MOV     CX, 01000h              ; Retry counter
          IN      AL, KBDSTATUS           ; Get keyboard status
            ; ? If keyboard buffer is empty, reset system
          JZ      RS_PulseReset
          LOOP    RS_WaitForKbd
          MOV     AX, 0FFFFh              ; Return failure
          JMP     RS_Return
          MOV     AL, CMDPULSEOUTPUTPORT  ; Pulse system reset port
          OUT     KBDSTATUS, AL
          MOV     AX, 0h                  ; Return success
          JMP     RS_WaitForKbd

          POP     BP
          RET     2             ; Clear stack from parameters passed

Figure 3.1.a

You may note that an argument is passed to this ring-2 function call. This will be explained in Figure 3.1.c in more detail.

Many articles have already covered calling ring-2 code from ring-3, so Figure 3.1.b is only included for completeness.


              RebootSystem=REBOOTSYSTEM   1
Figure 3.1.b

The most interesting thing is shown in Figure 3.1.c. You will surely notice, that RebootSystem() is called twice, once with the parameter FALSE and once with TRUE. RebootSystem(FALSE) calls the code in the IOPL segment without actually doing I/O programming to reset your workstation, however calling code in the IOPL segment ensures that the code is in memory, that is not paged out into the swapper or not loaded at all.

If we didn't do this, DosShutdown() would flush and close the file system, and if the IOPL segment wasn't in memory before calling DosShutdown() it would never be paged in or loaded. Of course, as only device drivers can lock memory, there is the possibility, that the IOPL segment gets paged out between the calls to RebootSystem(FALSE) and DosShutdown() but I would expect this to be very unlikely.

Finally, RebootSystem(TRUE) is called to perform the hardware reset.

  /* Call function RebootSystem() from our IOPL segment
     to ensure that all necessary code gets loaded now,
     because after DosShutdown(), no disk access is allowed
     anymore. Leaving out this call prevents the reboot
     from working (above explanation is what I assume,
     I don't know it exactly) */
Figure 3.1.c

I've excluded the code that informed the user on a dialog about the progress, and some DosSleep calls that gave the user some time to read messages. You may argue that DosSleep in a dialog procedure blocks PM (because blocking the message queue) and you are right, but once you have called DosShutdown() user input doen't make much sense anyway.


The undocumented DOS$ call has been published in the OS/2 development fora on the IBM PC conference disk and the InterNet NetNews. IPLing a PC through the system control port A and the keyboard controller has been published in verious IBM technical references.