目的:將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"; \
<span style="color:#003300;"><strong>echo "-e __start"; </strong></span> \
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 <span style="color:#000099;">defined(CONFIG_ARM)</span> && defined(_ASMLANGUAGE)
#if defined(CONFIG_ISA_THUMB2)
/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */
<span style="color:#000099;">#define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb</span>
#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
*
* <span style="color:#000099;">Vector table at the beginning of the image for starting system. The reset
* vector is the system entry point, ie. the first instruction executed.</span>
*
* 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
<span style="color:#000099;">.word __reset</span>
.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;