world leader in high performance signal processing
Trace: » bootloaders

Bootloaders in Bare metal development

Developing and debugging Bare metal applications generally requires JTAG tools. Using a JTAG interface, users can accurately debug the application running on the target. However, it is also possible to run / debug the ELF Image with the boot-loader concept. Since most of the boot loaders are expected to support debugging through serial and ethernet (which enables them to load and debug Linux images), the same concept may be utilized to debug a bare metal ELF image, though with limited support.

Boot loaders may vary in their support for bare metal debugging, but in general they should have these common functionalities:

  • Command and data transfer through serial.
  • Command and/or data transfer through ethernet.
  • Support for running and/or debugging ELF Image.
  • Support for gdb server.


Users may find the following features particularly useful for bare metal applications (especially without JTAG):

kgdb method

u-boot also supports kgdb to debug the Linux Kernel. This method maybe employed for debugging bare metal ELF Image also.

/* TO DO: list the commands here*/


uMon or micromonitor bootloader has some capabilities that can be utilized for ELF image running and debugging. This software can either work standalone or it can also co-exist with u-boot such that the u-boot can load the ELF image of this bootloader. The following output was taken from uMon running on BF537 EZ-KIT Lite.

Only the relevant commands are listed here. Refer to uMon pages for building and using the bootloader.

To create the uMon ELF image (bram.elf), refer to uMon documentation at uMon. Then, with the target running u-boot, the image is transferred to the target's memory…

bfin> tftp 0x1000000 bram.elf
Using bfin_mac device
TFTP from server; our IP address is
Filename 'bram.elf'.
Load address: 0x1000000
Loading: ######################################################
Bytes transferred = 786456 (c0018 hex)

Then u-boot loads bram.elf and turns over control to its entrypoint; which in turn gives control of the board to uMon command prompt.

bfin> bootelf 0x1000000
Loading phdr 0 to 0x02f00000 (289976 bytes)
## Starting application at 0x02f00000 ...tTFS altdevtbl[0] appears corrupt
TFS altdevtbl[1] appears corrupt
Misformed ethernet addr at: 0x20000010

                             MICRO MONITOR 1.18.17
                           Platform: ADDS-BF537-EVAL
                              CPU: BlackFin BF537
                         Built: Jun 22 2011 @ 18:37:39
                       Monitor RAM: 0x2f46cb8-0x2f61ea0
                        Application RAM Base: 0x100000
                                 CPU Version 3
uMON>help -i
Platform: ADDS-BF537-EVAL
CPU: BlackFin BF537
Built: Jun 27 2011 @ 18:11:56
Monitor RAM: 0x2f46d8c-0x2f61fc4
Application RAM Base: 0x100000
CPU Version 3
Stack: bottom=0x2f5f4e4, size=8192
Moncomptr:    0x02f00004
Etheradd_ptr: 0x20000010
AltTFSdevtbl: 0x20000030

Change parameters for network.

uMON>set ETHERADD 00:11:22:33:44:55
       PROMPT = uMON>
   APPRAMBASE = 0x100000
  BOOTROMBASE = 0x20000000
 MONITORBUILT = Jun 22 2011 @ 18:37:39
    MONCOMPTR = 0x2f00004
  TARGETTIMER = 0x2f000a2
        IPADD =
     ETHERADD = 00:11:22:33:44:55
uMON>ether on

Build the application ELF image. Note that the startup code of the bare metal application should not mess up with the Stack allocation done by uMon. It should also make sure to return back to uMon safely with mon_appexit(). An example that was compiled with '-nostartfiles' option is given below:

#include <cdefBF537.h>
#include <monlib.h>
extern unsigned char _bss_start, _bss_end;
int main(void);
void _start(void)
	register unsigned char *ramstart;
	ramstart = &_bss_start;
	while(ramstart < &_bss_end)
		*ramstart++ = 0;

/* Connect the application to the monitor. This must be done prior to the application making any other attempts to use the "mon_" functions provided by the monitor. */
	monConnect((int(*)())(*(unsigned long *)0x02f00004),(void *)0,(void *)0);

	int r = main();


int main(void)
	*pPORTF_FER 		= 0x0000;		// Setup for LEDs
	*pPORTFIO_DIR		= 0x0FC0;		// Setup port for output
	*pPORTFIO_SET		= 0x0FC0;		// Turn all LEDs on

	return 0;

Load and run the application image.

uMON>tftp -F bare -fE get bare_test_bf537
Retrieving bare_test_bf537 from
TFTP transfer complete.
Rcvd 177937 bytes
Adding bare (size=177937) to TFS...

Application Exit Status: 0 (0x0)

ELF Image can also be stored as a function that can be accessed via call command.

uMON>tfs -v ld bare
 .text     : copy    6704 bytes from 0x20102c1c to 0xffa00000
 .bss      : set      304 bytes  at  0xff800000 to 0x00
 .comment  :           72 bytes not processed (tot=72)
 .debug_aranges:           64 bytes not processed (tot=136)
 .debug_pubnames:         1305 bytes not processed (tot=1441)
 .debug_info:         9381 bytes not processed (tot=10822)
 .debug_abbrev:          628 bytes not processed (tot=11450)
 .debug_line:         1296 bytes not processed (tot=12746)
 .debug_frame:         1904 bytes not processed (tot=14650)
 .debug_str:         1636 bytes not processed (tot=16286)
 .debug_loc:         2418 bytes not processed (tot=18704)
 .debug_macinfo:       142844 bytes not processed (tot=161548)
 .shstrtab :          166 bytes not processed (tot=161714)
 .symtab   :         2832 bytes not processed (tot=164546)
 .strtab   :         1949 bytes not processed (tot=166495)
 entrypoint: 0xffa00000
Application Exit Status: 0 (0x0)

gdbserver on uMon

uMon can be configured with a gdb server running on Ethernet - to provide basic download and then post-mortem analysis. If there was a crash or exit, the “application code, data and their symbols” would still be in memory and gdb could be connected to uMon to symbolically look at state. Note that currently there is no support for using gdb as a runtime debugger.

At host, set up the gdb and debug symbolically (note: no breakpoint / step / run / continue). Some examples are given below.

C:\Program Files\Analog Devices\GNU Toolchain\2010R1\elf\bin>bfin-elf-gdb.exe bare_test_bf537
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "--host=i386-mingw32msvc --target=bfin-elf"...
(gdb) target remote udp:
warning: The remote protocol may be unreliable over UDP.
Some events may be lost, rendering further debugging impossible.
Remote debugging using udp:
warning: unrecognized item "OK" in "qSupported" response
0x00000000 in ?? ()
(gdb) print global_data
$3 = 5678
(gdb) print 0xff800000
$6 = 4286578688

Note that the debugging context is within the executed application. By forcing a return via exception, gdb can look inside the registers also.

#define EXCEPTION()     asm("excpt 5");     /* Force exception */

(gdb) info registers
r0             0x0      0
r1             0x40     64
r2             0xf870   63600
r3             0x2f4acfc        49589500
r4             0x2f5f0f4        49672436

Application can make use of the uMon in-built heap manager for dynamic allocations, instead of using the standard APIs. It gives a descriptive analysis of the allocation functions and usage. Note that the monitor itself uses malloc / free, so one would see additional numbers in the output. Application needs to call mon_malloc() & mon_free(p) to connect to the heap manager in the uMon. One example is given below.

Heap summary:
  Malloc/realloc/free calls:  99/0/47
  Malloc/free totals: 1604/812
  High-water level:   792
  Malloc failures:    0
  Bytes overhead:     1060
  Bytes currently allocated:   792
  Bytes free on current heap:  63684
  Bytes left in allocation pool:  0