Rebooting OS/2

Written by Roman Stangl

Using SETBOOT.EXE
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): 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 bellow. 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,     FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE |      OPEN_ACCESS_READWRITE, 0); if(apiretDosDD!=NO_ERROR) ... 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. Bellow listing shows the call to DosShutdown, though its quite well documented in the online reference. /* Shutdown the system anyway */ DosShutdown(0); 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).
 * For OS/2 2.11 and before add the line DEVICE=d:\OS2\DOS.SYS<(/tt>.
 * For OS/2 Warp add the line DEVICE=d:\OS2\BOOT\DOS.SYS.

You jump to the reboot vector by calling a function of the DOS$ device: if(NO_ERROR!=DosDevIOCtl(hfileDosDD, IOCTL_DOS, DOS_REBOOT, NULL, 0,                          NULL, NULL, 0,                          NULL)) ... Last but not least, Listing bellow shows the parameters for the undocumented interface of the DOS$ device to call the reboot vector, #define IOCTL_DOS                  0x00D5 #define DOS_REBOOT                 0x00AB 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 PCs 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 listing bellow which shows the assembler code to reboot a workstation by trying to force activation of the reset line: You may note that an argument is passed to this ring-2 function call. This will be explained in listing bellow in more detail.
 * 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.

Many articles have already covered calling ring-2 code from ring-3, so listing is only included for completeness. SEGMENTS CODEIOPL CLASS 'CODE' IOPL PRELOAD EXPORTS RebootSystem=REBOOTSYSTEM  1 The most interesting thing is shown in listing bellow. 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 any more. Leaving out this call prevents the reboot from working (above explanation is what I assume,    I don't know it exactly) */ RebootSystem(FALSE); DosShutdown(0); RebootSystem(TRUE); 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 doesn't make much sense anyway.

Credits
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 various IBM technical references.