Updated: October 28, 2024 |
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.
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.
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)