System reset

Updated: May 06, 2022

The kernel uses the reboot_*() callout to reboot the system.

This callout lets you customize what procnto's process manager needs to do when it restarts the system (for example, turn off the watchdog), without requiring changes to the process manager itself.

Any system shutdown request calls sysmgr_reboot(), which triggers the reboot_*() callout (see sysmgr_reboot() in the QNX Neutrino C Library Reference).

The reboot_*() callout should 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.

In some systems, it is impossible to implement a full reboot in the kernel callout. In such cases when software can't force a reboot, the reboot kernel callout should go into an endless loop, preventing any other activity (see the final instuction in the example below).

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 flag
     * 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 parameter flag
    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]
    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)