System reboot

Updated: April 19, 2023

The kernel invokes the reboot() callout to reboot the system.

This callout must do whatever work is needed to reset the system to a known good state.

If the C Library function of sysmgr_reboot() is called, the kernel invokes the reboot() callout (see sysmgr_reboot() in the QNX Neutrino C Library Reference) with an abnormal parameter setting of zero. This indicates a normal (i.e., user-requested) termination.

If the kernel detects a situation that prevents it from continuing to behave correctly, it invokes the same callout but with the abnormal parameter set to a non-zero value. This is an abnormal termination.

CAUTION:

For a deployed (production) system, the reboot callout must contain whatever platform-specific code is needed to reboot the system. In some cases, the reboot can be started by programming a watchdog timer to go off immediately; in other words, by forcing the watchdog to trigger the reboot.

For a development system, the callout can decide whether to reboot the system or instead halt execution to allow you to attach a debugger and investigate the processor state.

If you're using the default reboot callout, for which sample code is shown below, you must set the startup program's -A option to ensure the kernel actually reboots the system following an abnormal termination. (For a normal termination, this option doesn't apply, and the kernel always reboots the system.) This callout examines the SYSTEM_PRIVATE_FLAG_ABNORMAL_REBOOT bit, whose setting is based on that startup option, and if the bit isn't set, the callout just spins in a loop (see the final instuction in the example below). For more information, see the startup-* options entry in the Utilities Reference.

When you've finished debugging, there's no reason to leave this bit unset. The reboot callout must reboot the system, whether it's a normal or abnormal termination. So you always want to set the startup -A option once you've got working code for rebooting the system.

Examples

Below is a code sample for patching the kernel callout (for background information, see Patching the kernel callout code in this chapter):

#include "callout.ah"
#include <arm/elsinore1599.h>

/*
 * Routine to patch callout code
 *
 * On entry:
 *  r0 - physical address of syspage
 *  r1 - virtual  address of syspage
 *  r2 - offset from start of syspage to start of the callout routine
 *  r3 - offset from start of syspage to read/write data used by callout
 */

patch_reboot:
    stmdb    sp!, {r4, lr}
    add      r4, r0, r2

    /* Map PRM registers */
    mov      r0, #CM_PRCM_SIZE
    ldr      r1, Lpaddr
    bl       callout_io_map

    /* Patch the callout routine */
    CALLOUT_PATCH  r4, r0, r1, r2, ip
    ldmia    sp!, {r4, pc}

Lpaddr:     .word PRM_DEVICE_BASE + PRM_RSTCTRL

#define ARM_CPSR_T        (1 << 5)
#define ARM_CPSR_F        (1 << 6)
#define ARM_CPSR_I        (1 << 7)

Below is code for restarting a fictional ARM board:

CALLOUT_START(reboot_elsinore1599, 0, patch_reboot)
    /*
     * Get the base address of CLK & Reset registers (patched)
     * r0 = _syspage_ptr
     * r1 = abnormal termination parameter passed to callout
     * r2 assumed to be available as scratch register
     */

    mov     ip,     #0x000000FF
    orr     ip, ip, #0x0000FF00
    orr     ip, ip, #0x00FF0000
    orr     ip, ip, #0xFF000000

    teq        r1, #0      // r1 = abnormal termination parameter
    beq        _do_reboot

    ldrh       r2, [r0, #SYSPAGE_SYSTEM_PRIVATE] // offset to system_private
    add        r0, r0, r2  // system_private address
    ldr        r2, [r0, #SP_PRIVATE_FLAGS]
    /* r2 = ABNORMAL_REBOOT flag based on startup -A option */
    tst        r2, #SYSTEM_PRIVATE_FLAG_ABNORMAL_REBOOT
    beq        0f          // spin if ABNORMAL_REBOOT is NOT set

_do_reboot:
    mov        r1, #RST_GLOBAL_COLD_SW    //#RST_GLOBAL_WARM_SW
    str        r1, [ip]
/* if we get here there is nothing else we can do about it, so loop */
0:  b       0b

CALLOUT_END(reboot_elsinore1599)