目的:将zephyr搬到我的stm32F4 soc上。
移置当然是有个base,所以这里是stm32f1。第一步当然是cpu上电后执行的第一个命令。
找到镜像程序被cpu执行的第一条语句,那需要知道镜像文件的组成结构,
那么根据根目录下的Makefile,其指明编译zephyr镜像文件需要的链接脚本。
ifdef CONFIG_HAVE_CUSTOM_LINKER_SCRIPT
KBUILD_LDS := $(subst $(DQUOTE),,$(CONFIG_CUSTOM_LINKER_SCRIPT))
else
# Try a board specific linker file
KBUILD_LDS := $(srctree)/boards/$(BOARD_NAME)/linker.ld
# If not available, try an SoC specific linker file
ifeq ($(wildcard $(KBUILD_LDS)),)
KBUILD_LDS := $(srctree)/arch/$(ARCH)/soc/$(SOC_PATH)/linker.ld
endif
endif
CONFIG_CUSTOM_LINKER_SCRIPT=""中定义的优先级最高,接着使用board目录下的,最后使用arch目录下的链接文件。
目前stm32f1使用的文件是arch/arm/soc/st_stm32/stm32f1->include/arch/arm/cortex_m/scripts/linker.ld
而实际上知道了这个并没有什么用,你不知道镜像的第一条指令是由那条代码提供的。
仔细查看根目录的makefile,可以得到如下的参数设定:
quiet_cmd_create-lnk = LINK $@
cmd_create-lnk = \
( \
echo $(LDFLAGS_zephyr); \
echo "$(LINKFLAGPREFIX)-Map=$(O)/$(KERNEL_NAME).map"; \
echo "-L $(objtree)/include/generated"; \
echo "-u _OffsetAbsSyms -u _ConfigAbsSyms"; \
echo "-e __start"; \
echo "$(LINKFLAGPREFIX)--start-group"; \
echo "$(LINKFLAGPREFIX)--whole-archive"; \
echo "$(KBUILD_ZEPHYR_APP)"; \
echo "$(LINKFLAGPREFIX)--no-whole-archive"; \
echo "$(KBUILD_ZEPHYR_MAIN)"; \
echo "$(objtree)/arch/$(ARCH)/core/offsets/offsets.o"; \
echo "$(LINKFLAGPREFIX)--end-group"; \
echo "$(LIB_INCLUDE_DIR) $(LINK_LIBS)"; \
) > $@
其中颜色突出的部分即为镜像文件的入口点,__start。依稀记得学汇编程序的时候编写过链接脚本的,
而脚本中将指定程序的入口点。根据网络到的信息可以有以下几个方式来完成入口点的指定:
1:在连接的时候使用-e参数。
2:在脚本里使用ENTRY
3:如果定义过start这个入口(如果你在汇编里如果本身就有这个名字叫start的入口,那么不用特别的声明也可以)
4:SECTION中.text的第一个入口函数
5:地址为0的指令
优先级5为最低。
接下来需要找到这个__start为何物,这样才能开始我的stm32f4的zephyr之旅。
x86是从crt0.s这个文件开始的,但是arm没有这个文件。
搜索整个zephyr源码,得到如下结果:
./arch/arm/core/cortex_m/vector_table.h:49:GTEXT(__start)
而gcc.h中对GTEXT的定义为:
#define GTEXT(sym) .global FUNC(sym); .type FUNC(sym), %function
这,这,这声明了__start是个全局的函数,这只是声明,并没有找到__start的实现。未找到入口。
接着尝试ENTRY、start,未找到入口。
.text的第一个函数作为入口?这在哪儿去捞?
include/toolchain/gcc.h中找找看,看我找到了啥:
#if defined(CONFIG_ARM) && defined(_ASMLANGUAGE)
#if defined(CONFIG_ISA_THUMB2)
/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */
#define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb
#elif defined(CONFIG_ISA_THUMB)
#define _ASM_FILE_PROLOGUE .text; .code 16
#else
#define _ASM_FILE_PROLOGUE .text; .code 32
#endif
#endif
_ASM_FILE_PROLOGUE这个便是入口了?! vector_table.S中给出了答案。
/**
* @file
* @brief Populated vector table in ROM
*
* Vector table at the beginning of the image for starting system. The reset
* vector is the system entry point, ie. the first instruction executed.
*
* The table is populated with all the system exception handlers. The NMI vector
* must be populated with a valid handler since it can happen at any time. The
* rest should not be triggered until the kernel is ready to handle them.
*/
#define _ASMLANGUAGE
...
#include "vector_table.h"
_ASM_FILE_PROLOGUE
...
.word __CORTEXM_BOOT_MSP
.word __reset
.word __nmi
所以zephyr中关于stm32的入口函数便是找到了。接下来便是愉快的玩耍了。
这里需要说明下,cpu是从第2个word(int32)位置开始执行命令的,其跳过了第一个word。
参考:
http://www.cnblogs.com/cbs-soft/archive/2010/01/08/1642388.html
https://www.zephyrproject.org zephyr是啥。
以下是stm32f1所对应编译生成的linker.cmd文件的内容:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512*1K
SRAM (wx) : ORIGIN = 0x20000000, LENGTH = 64 * 1K
SYSTEM_CONTROL_SPACE (wx) : ORIGIN = 0xE000E000, LENGTH = 4K
SYSTEM_CONTROL_PERIPH (wx) : ORIGIN = 0x400FE000, LENGTH = 4K
}
SECTIONS
{
_image_rom_start = 0x08000000;
text :
{
KEEP(*(.exc_vector_table))
KEEP(*(".exc_vector_table.*"))
KEEP(*(.irq_vector_table))
KEEP(*(".irq_vector_table.*"))
KEEP(*(.security_frdm_k64f))
KEEP(*(".security_frdm_k64f.*"))
KEEP(*(.isr_irq*))
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9])))
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9])))
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9][0-9])))
_image_text_start = .;
*(.text)
*(".text.*")
*(.gnu.linkonce.t.*)
} > FLASH
_image_text_end = .;
devconfig () :
{
__devconfig_start = .;
*(".devconfig.*")
KEEP(*(SORT(".devconfig*")))
__devconfig_end = .;
} > FLASH
gpio_compat () :
{
__gpio_compat_start = .;
*(".gpio_compat.*")
KEEP(*(SORT(".gpio_compat*")))
__gpio_compat_end = .;
} > FLASH
.ARM.exidx :
{
__exidx_start = .;
*(.ARM.exidx* gnu.linkonce.armexidx.*)
__exidx_end = .;
} > FLASH
rodata :
{
*(.rodata)
*(".rodata.*")
*(.gnu.linkonce.r.*)
} > FLASH
_image_rom_end = .;
__data_rom_start = ALIGN(4);
datas : AT(__data_rom_start)
{
_image_ram_start = .;
__data_ram_start = .;
*(.data)
*(".data.*")
} > SRAM
initlevel () :
{
__device_init_start = .; __device_PRIMARY_start = .; KEEP(*(SORT(.init_PRIMARY[0-9]))); KEEP(*(SORT(.init_PRIMARY[1-9][0-9]))); __device_SECONDARY_start = .; KEEP(*(SORT(.init_SECONDARY[0-9]))); KEEP(*(SORT(.init_SECONDARY[1-9][0-9]))); __device_NANOKERNEL_start = .; KEEP(*(SORT(.init_NANOKERNEL[0-9]))); KEEP(*(SORT(.init_NANOKERNEL[1-9][0-9]))); __device_MICROKERNEL_start = .; KEEP(*(SORT(.init_MICROKERNEL[0-9]))); KEEP(*(SORT(.init_MICROKERNEL[1-9][0-9]))); __device_APPLICATION_start = .; KEEP(*(SORT(.init_APPLICATION[0-9]))); KEEP(*(SORT(.init_APPLICATION[1-9][0-9]))); __device_init_end = .;
} > SRAM
_k_task_list () :
{
_k_task_list_start = .;
*(._k_task_list.public.*)
*(._k_task_list.private.*)
_k_task_list_idle_start = .;
*(._k_task_list.idle.*)
KEEP(*(SORT("._k_task_list*")))
_k_task_list_end = .;
} > SRAM
_k_task_ptr () :
{
_k_task_ptr_start = .;
*(._k_task_ptr.public.*)
*(._k_task_ptr.private.*)
*(._k_task_ptr.idle.*)
KEEP(*(SORT("._k_task_ptr*")))
_k_task_ptr_end = .;
} > SRAM
_k_pipe_ptr () :
{
_k_pipe_ptr_start = .;
*(._k_pipe_ptr.public.*)
*(._k_pipe_ptr.private.*)
KEEP(*(SORT("._k_pipe_ptr*")))
_k_pipe_ptr_end = .;
} > SRAM
_k_mem_map_ptr () :
{
_k_mem_map_ptr_start = .;
*(._k_mem_map_ptr.public.*)
*(._k_mem_map_ptr.private.*)
KEEP(*(SORT("._k_mem_map_ptr*")))
_k_mem_map_ptr_end = .;
} > SRAM
_k_event_list () :
{
_k_event_list_start = .;
*(._k_event_list.event.*)
KEEP(*(SORT("._k_event_list*")))
_k_event_list_end = .;
} > SRAM
__data_ram_end = .;
bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start = .;
*(.bss)
*(".bss.*")
*(COMMON)
__bss_end = ALIGN(4);
} > SRAM
noinit (NOLOAD) :
{
*(.noinit)
*(".noinit.*")
} > SRAM
_image_ram_end = .;
_end = .;
__bss_num_words = (__bss_end - __bss_start) >> 2;
.scp (NOLOAD) :
{
*(.scp)
*(".scp.*")
} > SYSTEM_CONTROL_PERIPH
.scs (NOLOAD) :
{
*(.scs)
*(".scs.*")
} > SYSTEM_CONTROL_SPACE
initlevel_error () :
{
KEEP(*(SORT(.init_[_A-Z0-9]*)))
}
ASSERT(SIZEOF(initlevel_error) == 0, "Undefined initialization levels used.")
}
__data_size = (__data_ram_end - __data_ram_start);
__data_num_words = (__data_size + 3) >> 2;