GDB can be used to debug Linux if required, but there are difficulties with handling virtual addresses with a "bare metal" debugger. A page miss would require execution of the relevant exception handler. As a consequence, all access via the current GDB implementation is to and from physical addresses, bypassing caches and MMUs if present.
The eventual solution will be to port KGDB (kgdb.linsyssoft.com), which knows how to handle memory in the kernel.
Sometimes just inserting printk
statements is
sufficient. The problem is that the kernel print function,
printk
does not work until the serial driver is
up and running. Problems earlier than this (very likely during the
early stages of porting) will be hidden.
The solution is to patch printk
to use the
internal simulator print facilities. Use of Or1ksim
simprintf
direct from printk
is not appropriate, since its argument is a pointer and at the time of
calling, the whole virtual memory system may be in flux.
However printk
calls vprintk
which does the complex work of building the final output string from
the format string and arguments. This string can then be printed a
character at a time using the Or1ksim NOP_PUTC
feature. Since characters are passed in registers, not as pointers, the
issue of virtual memory does not arise.
The implementation of the printk
can be found
in kernel/printk.c
in the Linux directory. In
there find the vprintk
function. Immediately
before it add two functions to write a string one character at a time
using the Or1ksim NOP_PUTC
feature.
#define NOP_PUTC 4 static void simputc( char c ) { asm( "l.or r3,r0,%0" : : "r" (c)); asm( "l.nop %0" : : "K" (NOP_PUTC)); } /* simputc() */ static void simputs( char *str ) { int i = 0; for( i = 0 ; str[i] != '\0' ; i++ ) { simputc( str[i] ); } } /* simputs() */
Then find the line in vprintk
where the formatted
string is constructed in the printk_buf
:
printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
Immediately after this use the new simputs
function to print this string to the console via Or1ksim.
simputs( printk_buf ); /* For Or1ksim */
Rebuild Linux (see Section 3.4) and run again under the simulator. The Linux kernel output will appear in the window from which the simulator was run.
<... Or1ksim startup messages ...> Copying Linux... Ok, booting the kernel. ****************** counters reset ****************** cycles 145321226, insn #9988651 ****************** counters reset ****************** <5>Linux version 2.6.23-or32 (jeremy@thomas) (gcc version 3.4.4) #3 Sat Jun 28 1 9:30:06 BST 2008 Detecting Processor units: Signed 0x391 Setting up paging and PTEs. write protecting ro sections (0xc0002000 - 0xc024c000) Setting up identical mapping (0x80000000 - 0x90000000) Setting up identical mapping (0x92000000 - 0x92002000) Setting up identical mapping (0xb8070000 - 0xb8072000) Setting up identical mapping (0x97000000 - 0x97002000) Setting up identical mapping (0x99000000 - 0x9a000000) Setting up identical mapping (0x93000000 - 0x93002000) <... Lots more kernel messages ...> <5>VFS: Disk quotas dquot_6.5.1 Dquot-cache hash table entries: 2048 (order 0, 8192 bytes) <6>Installing knfsd (copyright (C) 1996 okir@monad.swb.de). <6>io scheduler noop registered <6>io scheduler anticipatory registered (default) <6>io scheduler deadline registered <6>io scheduler cfq registered <6>Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing disabled <6>serial8250.0: ttyS0 at MMIO 0x90000000 (irq = 2) is a 16550A <... Serial I/O now working! ...> init started: BusyBox v1.4.1 (2007-03-22 18:53:56 EST) multi-call binary Starting pid 22, console /dev/ttyS0: '/etc/init.d/rcS'
The kernel does not lose messages, it saves them until serial I/O is available and then prints them, so once the 8250 is initialized, everything will appear on the console and on the xterm used by the Or1ksim UART.
That concludes this application note. Enjoy the tools!