System reboot
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 OS 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.
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
Patching the kernel callout code):
#include "callout.ah"
#include <arm/elsinore1599.h>
/*
* Routine to patch callout code
* 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)
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)