青春无悔
分类: 嵌入式
2014-11-10 16:37:52
Since the LDR format has the ability to execute small pieces of code (init blocks), as well as load chunks of code into specific memory addresses, the startup sequence process is streamlined nicely. For a general overview of the LDR process, please see .
Here we will start at the ELF entry point of U-Boot which is cpu/blackfin/start.S:_start(). When booting in bypass mode (parallel flash), or using the U-Boot gocommand, this is the first thing executed.
All of these options are placed into your board configuration file. They require a CONFIG_ prefix to be added (it has been omitted here for readability).
When an unhandled exception or interrupt occurs, the state of the processor will be dumped to the console as well as the hardware trace buffer. You can use this information to easily locate the code that triggered the exception.
For more in-depth information for how to use the hardware trace effectively as well as some examples, see the document.
This option adds little overhead in terms of code size (1 kB) and adds no runtime overhead as it is only executed when an unhandled exception occurs -- which should never happen in at runtime.
The normal dump output will only include undecoded addresses. You need to translate them by hand to the actual symbols by comparing them to the objdump output of the U-Boot ELF. This can get tedious very quickly while doing development, so this option will embed the symbol table in the U-Boot binary. When a dump occurs, the addresses will be translated automatically so the output will include both the address and the associated symbol.
This option adds quite a bit of overhead in terms of code size (11 kB) but adds no runtime overhead as it is only executed by the dump code mentioned above.
This will turn on serial output as early as possible (almost at power on) so that status messages will be constantly written to the UART console. Additional status messages will also be enabled at significant steps in the booting process.
The actual early implementation details can be found in the cpu/blackfin/serial.h and cpu/blackfin/serial.c files.
This option adds little overhead in terms of code size (2 kB) but adds runtime overhead and output that is really only suitable for debugging.
If you have code that may be accessing initialized data (or NULL pointers), then you can catch them. This will cover the start of memory (first 1kB) with two CPLB's. That way, any memory access to that region (data or instruction) will cause an exception. Any unhandled exceptions will cause a processor dump (see the DEBUG_DUMPoptions).
Keep in mind that any valid accesses will also be flagged, so this should only be enabled during development. You will be unable to use standard U-Boot commands such as memory display, copy, fill, etc… on the protected memory region.
This option adds little overhead (~70 bytes), but prevents the start of memory from being used.
This option is pretty straight forward. Upon a crash that would automatically reset the board, the board will instead hang and constantly execute the emuexcpt instruction. If a JTAG ICE is hooked up, it will automatically be triggered.
While not strictly a debug option, it can be quite useful while debugging remotely. This will enable the on-chip Blackfin hardware watchdog right after power on, and then common pieces of U-Boot will routinely poke it. If some piece of code gets hung up, the watchdog will reset the processor.
If you're booting an LDR image, you should use a “largish” timeout value here as the processor will not be able to poke the watchdog until the LDR has finished completely loading. When booting over the UART or slow SPI devices, it can take a few seconds before U-Boot can take over. The default timeout is set to 20 seconds.
Once U-Boot has started executing (before initialization/relocation), the watchdog will be programmed with a 5 second timeout. If your initialization process can take a while, increase this timeout as needed.
The most common problem people hit is external memory setup. Either the hardware is not solid and so cannot run at all or at the max theoretical frequency, or the timings are wrong for the specified SCLK and memory part.
This is often observed when enabling early serial debug and then only seeing a string of letters that end in >.
Rather than figure out the timings yourself, read the page (and in particular, read the spreadsheet at the bottom).
If things still aren't working, slow down the timings from whatever the memory datasheet says. Once you have a known working configuration, you can try speeding things back up until they fail, and then reviewing the hardware signals to fix any problems there.
It might also be helpful to connect a JTAG device and examine external memory to make sure the contents match exactly the u-boot binary that should be there. Failing memory devices/timings will show random bit errors.
Sometimes it is useful to load U-Boot directly up into external memory and bypass the flash programming process. Here are a few notes to show you how with GDB and aJTAG connection. By themselves, these commands will not work. You have to connect to a remote jtag target first, so see the if you need more information.
First, since GDB will load things directly into external memory, we need to make sure external memory has been set up properly first. Normally this is handled by the Boot ROM calling our initcode, but since we are bypassing the Boot ROM, we need to load it by hand.
Start with a simple piece of code like so (call it init.S):
#include/blackfin.h> .global __start __start: sp.l = LO(L1_SRAM_SCRATCH_END - 20); sp.h = HI(L1_SRAM_SCRATCH_END - 20); call _initcode;1: emuexcpt; jump 1b;.size __start, .-__start
Then just link it against the initcode to produce a standalone ELF like so (make sure to replace the -mcpu argument with the appropriate value for your board):
$ bfin-elf-gcc -nostartfiles init.S arch/blackfin/cpu/initcode.o -o init.elf -Iinclude -D__ASSEMBLY__ -mcpu=bf547
Now, armed with these two ELF's (init.elf and u-boot), we can get things running with GDB.
The important commands we run are:
Here is a sample run. Note that the addresses and sizes may be significantly different from your setup -- that is perfectly normal!
If you're using this procedure repeatedly, enter this sequence in .gdbinit (working directory)
$ bfin-elf-gdb ./u-boot (gdb) set remotetimeout 300 ... connect to your jtag device ... (gdb) load init.elf Loading section .text, size 0x32c lma 0xffa00000 Start address 0xffa0031c, load size 812 Transfer rate: 1676 bits/sec, 812 bytes/write. (gdb) c Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0xffa00328 in ?? () (gdb) load u-boot Loading section .text, size 0xa778 lma 0xfeb00000 Loading section .rodata, size 0x31e4 lma 0xfeb0a778 Loading section .data, size 0x2300 lma 0xfeb0d95c Loading section .u_boot_cmd, size 0x280 lma 0xfeb0fc5c Loading section .text_l1, size 0x40 lma 0xfeb0fedc Start address 0xfeb00000, load size 65308 Transfer rate: 7829 bits/sec, 9329 bytes/write. (gdb) call memset(&_bss_vma, 0, &_bss_len) (note for BF609 board you may skip this) warning: Unable to restore previously selected frame. $6 = 0xfeb0ff1c Current language: auto; currently asm (gdb) c Continuing.
Here we show a typical system that has 4megs of external memory. The memory regions above the asynchronous memory will differ depending on your Blackfin variant, so consult the appropriate datasheet for exact addresses if you really want to know.
0xffe00000: Blackfin Core MMRs ... 0xffc00000: Blackfin System MMRs ... 0xef000000: Boot ROM jump table ... 0x20000000: Start of asynchronous memory ... 0x01000000: CONFIG_SYS_MAX_RAM_SIZE: End of external memory 0x00f80000: CONFIG_SYS_MONITOR_BASE: Relocated U-Boot image 0x00f20000: CONFIG_SYS_MALLOC_BASE: U-Boot's dynamic heap for malloc() 0x00f1ffb0: CONFIG_SYS_GBL_DATA_ADDR: U-Boot's static "global data" region 0x00f1ff70: CONFIG_SYS_BD_INFO_ADDR: U-Boot's static "board info" region 0x00f1ff6c: CONFIG_STACKBASE: U-Boot's stack: grows "down" 0x00f1df70: CONFIG_SYS_MEMTEST_END: End address for U-Boot's memory test code ... 0x00000000: CONFIG_SYS_SDRAM_BASE/CONFIG_SYS_MEMTEST_START: Start of external memory
If you only define the relevant size's (CONFIG_SYS_MONITOR_LEN and CONFIG_SYS_MALLOC_LEN), then you will get a memory layout such as this automatically.
If you start relocating pieces though (such as putting the global data or stack into on-chip memory), then you will need to define all of the memory regions accordingly. Otherwise the mismatch of custom addresses and automatic placement will result in an invalid memory layout.
Review the common documentation (the top level README file) for more information on these.
CONFIG_SYS_MONITOR_BASE - Base address where U-Boot executes CONFIG_SYS_MONITOR_LEN - Size of the monitor region CONFIG_SYS_MALLOC_BASE - Base address of U-Boot's dynamic heap CONFIG_SYS_MALLOC_LEN - Size of the heap CONFIG_SYS_GBL_DATA_ADDR - Base address of U-Boot's global data GENERATED_BD_INFO_SIZE - Size of the global data w/padding (calculated automatically) CONFIG_SYS_BD_INFO_ADDR - Base address of U-Boot's global data GENERATED_BD_INFO_SIZE - Size of the board info w/padding (calculated automatically) CONFIG_STACKBASE - Base address of U-Boot's stack (which grows down) /* These are Blackfin specific */ CONFIG_LINUX_CMDLINE_ADDR - Base address for the Linux kernel command line CONFIG_LINUX_CMDLINE_SIZE - Largest string that may be passed
01OUTPUT_ARCH(bfin)
02MEMORY 03{ 04 ram : ORIGIN = ((16 * 1024 * 1024) - (512 * 1024)), LENGTH = (512 * 1024) 05 l1_code : ORIGIN = 0xFFA00000, LENGTH = (0xFFA07FFF - 0xFFA00000 + 1) 06 l1_data : ORIGIN = 0xFF900000, LENGTH = (0xFF903FFF - 0xFF900000 + 1) 07} 08ENTRY(_start) 09SECTIONS 10{ 11 .text.pre : 12 { 13 arch/blackfin/cpu/start.o (.text .text.*) 14 15 } >ram 16 .text.init : 17 { 18 arch/blackfin/cpu/initcode.o (.text .text.*) 19 } >ram 20 __initcode_lma = LOADADDR(.text.init); 21 __initcode_len = SIZEOF(.text.init); 22 .text : 23 { 24 *(.text .text.*) 25 } >ram 26 .rodata : 27 { 28 . = ALIGN(4); 29 *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) 30 . = ALIGN(4); 31 } >ram 32 .data : 33 { 34 . = ALIGN(4); 35 *(.data .data.*) 36 *(.data1) 37 *(.sdata) 38 *(.sdata2) 39 *(.dynamic) 40 CONSTRUCTORS 41 } >ram 42 .u_boot_list : { 43 KEEP(*(SORT(.u_boot_list*))); 44 } >ram 45 .text_l1 : 46 { 47 . = ALIGN(4); 48 __stext_l1 = .; 49 *(.l1.text) 50 . = ALIGN(4); 51 __etext_l1 = .; 52 } >l1_code AT>ram 53 __text_l1_lma = LOADADDR(.text_l1); 54 __text_l1_len = SIZEOF(.text_l1); 55 ASSERT (__text_l1_len <= (0xFFA07FFF - 0xFFA00000 + 1), "L1 text overflow!") 56 .data_l1 : 57 { 58 . = ALIGN(4); 59 __sdata_l1 = .; 60 *(.l1.data) 61 *(.l1.bss) 62 . = ALIGN(4); 63 __edata_l1 = .; 64 } >l1_data AT>ram 65 __data_l1_lma = LOADADDR(.data_l1); 66 __data_l1_len = SIZEOF(.data_l1); 67 ASSERT (__data_l1_len <= (0xFF903FFF - 0xFF900000 + 1), "L1 data overflow!") 68 .bss : 69 { 70 . = ALIGN(4); 71 *(.sbss) *(.scommon) 72 *(.dynbss) 73 *(.bss .bss.*) 74 *(COMMON) 75 . = ALIGN(4); 76 } >ram 77 __bss_vma = ADDR(.bss); 78 __bss_len = SIZEOF(.bss); 79} |