AnsweredAssumed Answered

Debugging Application in KDS with Bootloader

Question asked by Ben Hefner on Apr 28, 2016
Latest reply on Jun 2, 2016 by Ben Hefner


I'm working on a custom bootloader and I'm having some problems with the debug configuration for my application. I've got a binary build set up and I've tested that I can jump to it from the bootloader.

 

I started with the Processor Expert linker files and have adapted them for my application. The target micro is an MK64FN1M0xxx12. I've got a config working with the application located at 0x0, and have had no problems with debugging it before moving it to make room for my bootloader. I'm using a Segger J-Link.

 

The problem I'm having is with my debug build configuration. When I start the debugger (flash & debug), the PC is at 0x0, unless I set a program counter in the debug configurations/start options. My application lives at 0x5800. The vector table starts at 0x5800, and is 0x198 bytes long, application starts at 0x5C00. I _think_ my problem might be setting the VTOR register, but GDB doesn't seem to know what that is, reporting "unsupported register !" when I try to write to vtor and scb->vtor. I've also tried writing it on startup manually using the EmbSys register plugin, to no avail. The debugger doesn't help once the application's started, the PC seems to jump from one end of the memory space to the other.

 

Summary:

  • I'm writing the flash configuration region at 0x400
  • Bootloader vector table starts at 0x0, runs to 0x198
  • Bootloader application starts at 0x410, ends at to 0x57fff
  • Application starts at 0x5800, ends at 0xfffff
  • SP gets set to 0xFFFFFFFC when not set by GDB
  • Application does not proceed into startup code when PC is set to 0x5800 or 0x5804
  • Writing the VTOR using the EmbSys register view doesn't seem to fix anything.
  • I've verified the flash config section, application vector table, and application are all in the right places in memory.

 

What I've tried so far:

  • startup options:
    • set PC to 0x5800
    • set PC to 0x5804
    • Set executable and symbols offset to 0x5800 (with both of the above PC locations)
  • Writing 0x5800 to the VTOR with GDB
  • Writing 0x5800 to the SP with GDB
  • Writing 0x2002FFF0 to the SP with GDB (I've located a struct shared by the main app and bootloader at the end of RAM, so I moved the stack pointer down to accomodate.)

 

Questions:

  • How do I get this working? I want to be able to debug the application at the correct address, and ideally, be able to run it without flashing the bootloader on the micro.
  • What do the executable and symbol offsets do in the debug config/startup options? I haven't seen any difference in the registers I'm looking at (PC, SP, VTOR).
  • Are there any other registers (besides PC, SP, VTOR) that I need to be concerned with to get this working?
  • Is it possible to set register init values in the linker file? It'd be nice if the application would still run without the debugger attached.
  • Does anyone know of any good (complete and well-explained) reference materials for the GDB settings in KDS? for GCC linker file settings?
  • Any other advice for resolving these kinds of issues?
  • Is there any difference between using 'set $<register> = <value>' and 'monitor reg <register> = <value>'?

 

Please let me know if you need anything else from me.

Thanks!

 

Linker file:

/* Entry Point */ ENTRY(__thumb_startup)   /* Highest address of the user mode stack */ /*_estack = 0x20030000;    had to move this because of the shared variable.*/ _estack = 0x2002FFF0; __SP_INIT = _estack; __stack = _estack;   /* Generate a link error if heap and stack don't fit into RAM */ __heap_size = 0x00;                    /* required amount of heap  */ __stack_size = 0x0400;                 /* required amount of stack */   MEMORY {   m_interrupts (RX) : ORIGIN = 0x00005800, LENGTH = 0x00000198   m_text      (RX) : ORIGIN = 0x00005C00, LENGTH = 0x000FA3FF   m_data_1FFF0000 (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000   m_data      (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000   m_cfmprotrom  (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 }   /* Define output sections */ SECTIONS {   /******************************************************************************/   /*******************************app sections***********************************/   /*data shared between application and bootloader. The NOLOAD parameter is used to prevent jumps between applications from causing re-initialization of the data.*/   .BootloaderSharedData 0x2002FFF8 (NOLOAD):   {     KEEP(*(.BootloaderSharedData)) /* keep my variable even if not referenced */   } > m_data   /******************************************************************************/     /* The startup code goes first into INTERNAL_FLASH */   .interrupts:   {     __vector_table = .;     . = ALIGN(4);     KEEP(*(.vectortable)) /* Startup code */     . = ALIGN(4);   } > m_interrupts     .cfmprotect :   {     . = ALIGN(4);   KEEP(*(.cfmconfig)) /* Flash Configuration Field (FCF) */   . = ALIGN(4);   } > m_cfmprotrom      /* The program code and other data goes into INTERNAL_FLASH */   .text :   {     . = ALIGN(4);     *(.text)           /* .text sections (code) */     *(.text*)          /* .text* sections (code) */     *(.rodata)         /* .rodata sections (constants, strings, etc.) */     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */     *(.glue_7)         /* glue arm to thumb code */     *(.glue_7t)        /* glue thumb to arm code */     *(.eh_frame)       KEEP (*(.init))     KEEP (*(.fini))       . = ALIGN(4);       _etext = .;        /* define a global symbols at end of code */   } > m_text      .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > m_text     .ARM : {     __exidx_start = .;       *(.ARM.exidx*)       __exidx_end = .;   } > m_text    .ctors :   {     __CTOR_LIST__ = .;     /* gcc uses crtbegin.o to find the start of        the constructors, so we make sure it is        first.  Because this is a wildcard, it        doesn't matter if the user does not        actually link against crtbegin.o; the        linker won't look for a file to match a        wildcard.  The wildcard also means that it        doesn't matter which directory crtbegin.o        is in.  */     KEEP (*crtbegin.o(.ctors))     /* We don't want to include the .ctor section from        from the crtend.o file until after the sorted ctors.        The .ctor section from the crtend file contains the        end of ctors marker and it must be last */     KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))     KEEP (*(SORT(.ctors.*)))     KEEP (*(.ctors))     __CTOR_END__ = .;   } > m_text     .dtors :   {     __DTOR_LIST__ = .;     KEEP (*crtbegin.o(.dtors))     KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))     KEEP (*(SORT(.dtors.*)))     KEEP (*(.dtors))     __DTOR_END__ = .;   } > m_text     .preinit_array     :   {     PROVIDE_HIDDEN (__preinit_array_start = .);     KEEP (*(.preinit_array*))     PROVIDE_HIDDEN (__preinit_array_end = .);   } > m_text   .init_array :   {     PROVIDE_HIDDEN (__init_array_start = .);     KEEP (*(SORT(.init_array.*)))     KEEP (*(.init_array*))     PROVIDE_HIDDEN (__init_array_end = .);   } > m_text   .fini_array :   {     PROVIDE_HIDDEN (__fini_array_start = .);     KEEP (*(SORT(.fini_array.*)))     KEEP (*(.fini_array*))     PROVIDE_HIDDEN (__fini_array_end = .);     ___ROM_AT = .;   } > m_text   /* Initialized data sections goes into RAM, load LMA copy after code */   .data : AT(___ROM_AT)   {     . = ALIGN(4);     _sdata = .;        /* create a global symbol at data start */     *(.data)           /* .data sections */     *(.data*)          /* .data* sections */       . = ALIGN(4);       _edata = .;        /* define a global symbol at data end */   } > m_data     ___data_size = _edata - _sdata;   ___m_data_1FFF0000_ROMStart = ___ROM_AT + SIZEOF(.data);   .m_data_1FFF0000 : AT(___m_data_1FFF0000_ROMStart)   {      . = ALIGN(4);      ___m_data_1FFF0000_RAMStart = .;      *(.m_data_1FFF0000) /* This is an User defined section */      ___m_data_1FFF0000_RAMEnd = .;      . = ALIGN(4);   } > m_data_1FFF0000   ___m_data_1FFF0000_ROMSize = ___m_data_1FFF0000_RAMEnd - ___m_data_1FFF0000_RAMStart;          /* Uninitialized data section */   . = ALIGN(4);   .bss :   {     /* This is used by the startup in order to initialize the .bss section */     __START_BSS = .;    PROVIDE ( __bss_start__ = __START_BSS );       *(.bss)     *(.bss*)     *(COMMON)       . = ALIGN(4);     __END_BSS = .;    PROVIDE ( __bss_end__ = __END_BSS );   } > m_data     _romp_at = ___ROM_AT + SIZEOF(.data) +SIZEOF(.m_data_1FFF0000);   .romp : AT(_romp_at)   {     __S_romp = _romp_at;     LONG(___ROM_AT);     LONG(_sdata);     LONG(___data_size);     LONG(___m_data_1FFF0000_ROMStart);     LONG(___m_data_1FFF0000_RAMStart);     LONG(___m_data_1FFF0000_ROMSize);     LONG(0);     LONG(0);     LONG(0);   } > m_data      text_end = ORIGIN(m_text) + LENGTH(m_text);   data_init_end = ___m_data_1FFF0000_ROMStart + SIZEOF(.m_data_1FFF0000) + SIZEOF(.romp);   ASSERT( data_init_end <= text_end, "region m_text overflowed with text and data")      /* User_heap_stack section, used to check that there is enough RAM left */   ._user_heap_stack :   {     . = ALIGN(4);     PROVIDE ( end = . );     PROVIDE ( _end = . );     PROVIDE ( __end__ = . );     __heap_addr = .;     __HeapBase = .;     . = . + __heap_size;     __HeapLimit = .;     . = . + __stack_size;     . = ALIGN(4);   } > m_data     .ARM.attributes 0 : { *(.ARM.attributes) } }

Outcomes