Kernel debug

Updated: April 19, 2023

The kernel uses the debug callouts when it needs to print out some internal debugging information or encounters a fault.

The kernel uses these callouts to interact with a serial port, console, or other device to output debug or instrumentation information. For example, a display_msg command in a boot image startup script can make procnto use a debug kernel callout to output a message like the following one:

Running default qnxbasedma.build...

We recommend that when working on a startup program, you start by getting a debug kernel callout working. The ability to output messages to a device helps you debug code as you add or modify it.

Kernel callouts

break_detect()
Check if a break has been detected.
display_char()
Receive a char from the kernel and output it to UART or another device.
poll_key()
Pass a char, if available, to the kernel. If no char is available, pass back -1.
spare()
Currently unused by the kernel; reserved for future usage.

Only the display_char() callout is required; the others are optional.

Example

This kernel callout takes a character passed in through register r4 and outputs it to the serial controller.

The CALLOUT_START macro's third argument invokes the patch_debug() routine. This routine replaces the 0x1234 and 0x5678 memory locations with the base address of the serial controller register. The lis (load immediate and shift) and ori (OR immediate) instructions load the base address of the UART registers into r6:

CALLOUT_START display_char_5200, 0, patch_debug
lis   %r6,0x1234
ori   %r6,%r6,0x5678

Disable interrupts:

loadi  %r9,PPC_MSR_EE
mfmsr  %r8
andc   %r9,%r8,%r9
mtmsr  %r9
isync

Loop until the Transmit Ready bit has been set:

1:
lwz    %r0,MGT5200_PSC_SR(%r6)
andis. %r0,%r0,MGT5200_PSC_SR_TXRDY
beq    1b

Store the byte (the char passed in by the kernel in r4) in the Transmit Byte register:

stb    %r4,MGT5200_PSC_TB(%r6)
eieio

Re-enable interrupts, then branch to the link register and continue executing at the instruction that follows the call to this routine:

mtmsr  %r8
isync
blr

End of callout marker:

CALLOUT_END display_char_5200
Note: The startup code must look after some specific debug tasks in addition to those handled by the kernel callouts (see Debug startup tasks in the Startup Programs chapter).