The kernel uses the reboot_*() kernel callout to reboot the system.
The reboot_*() kernel 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 this process manager (see procnto* in the Utilities Reference).
A request to shutdown calls sysmgr_reboot(), which triggers the reboot_*() kernel callout (see sysmgr_reboot() in the QNX Neutrino C Library Reference).
The reboot_*() kernel 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 not be possible 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 kernel callout example below).
The examples below show:
Below is the code for patching the kernel callout (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)