從洪荒時代,要啓航到原始社會了,準備。
那麼stm32f1 cpu上電後第一條指令__reset代碼:
_ASM_FILE_PROLOGUE
GTEXT(__reset)
/* lock interrupts: will get unlocked when switch to main task */
movs.n r0, #_EXC_IRQ_DEFAULT_PRIO //默認優先級
msr BASEPRI, r0<span style="white-space:pre"> </span>//設置BASEPRI(基本優先級),當優先級不小於這個值時,cpu不處理異常
/*
* Set PSP and use it to boot without using MSP, so that it
* gets set to _interrupt_stack during nanoInit().
*/
ldr r0, =__CORTEXM_BOOT_PSP
msr PSP, r0 <span style="font-family: Arial, Helvetica, sans-serif;">//設置PSP爲sdram的末端0x100個字節。</span>
movs.n r0, #2 /* switch to using PSP (bit1 of CONTROL reg) */
msr CONTROL, r0//使能PSP作爲堆棧指針
#ifdef CONFIG_WDOG_INIT
/* board-specific watchdog initialization is necessary */
bl _WdogInit //如果有加看門狗,初始化看門狗喲,移置之初,關掉它嘛。
#endif
b _PrepC //跳轉準備C程序的執行環境。
接着_PrepC:
/**
*
* @brief Prepare to and run C code
*
* This routine prepares for the execution of and runs C code.
*
* @return N/A
*/
void _PrepC(void)
{
relocate_vector_table();//保存中斷向量表到結構體__scs(0xe000e000)
bssZero();//清理BSS區
dataCopy();//XIP時拷貝rom數據到ram。eXecute In Place,即芯片內執行,指應用程序可以直接在flash閃存內運行,不必再把代碼讀到系統RAM中。
_Cstart();//開始進入到C的執行環境
CODE_UNREACHABLE;
}
_Cstart完成的工作包括:
a、完成中斷子系統的初始化,以便在做硬件初始化的時候開啓中斷相應。
b、完成主要硬件的初始化。
c、初始化隨機數產生器。
d、初始化堆棧金絲雀,金絲雀存放於棧上的局部變量和返回指針之間,用於檢測堆棧溢出
e、切換到主任務。入口爲_main。
以下爲_Cstart的源碼:
/**
*
* @brief Initialize nanokernel
*
* This routine is invoked when the system is ready to run C code. The
* processor must be running in 32-bit mode, and the BSS must have been
* cleared/zeroed.
*
* @return Does not return
*/
FUNC_NORETURN void _Cstart(void)
{
/* floating point operations are NOT performed during nanokernel init */
char dummyTCS[__tTCS_NOFLOAT_SIZEOF];
/*
* Initialize nanokernel data structures. This step includes
* initializing the interrupt subsystem, which must be performed
* before the hardware initialization phase.
*/
nano_init((struct tcs *)&dummyTCS);//初始化指明中斷向量的優先級變量的值爲默認值;創建_main 任務線程
/* perform basic hardware initialization */
<pre name="code" class="cpp"><span style="white-space:pre"> </span>//執行第一階段初始化。像linux一樣,系統的初始化需要一定的過程,那些部分需要先初始化,那些後,需要去安排。
<span style="white-space:pre"> </span>//如何安排的?通過SYS_INIT、DEVICE_INIT、DEVICE_INIT_PM帶上不同的初始話級別,【0~4】。在編譯的時
<span style="white-space:pre"> </span>//候便指定到目標文件中(zephyr鏡像文件),可以查看前文後附的鏈接腳本。<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 15px; line-height: 35px;"> </span>其中SYS_INIT簡單的<span style="font-family: Arial, Helvetica, sans-serif;">對DEVICE_INIT進行了包裝。</span>
_sys_device_do_config_level(_SYS_INIT_LEVEL_PRIMARY);/* * Initialize random number generator * As a platform may implement it in hardware, it has to be * initialized after rest of hardware initialization and
* before stack canaries that use it */RAND32_INIT();/* initialize stack canaries */STACK_CANARY_INIT();//金絲雀/* display boot banner */PRINT_BOOT_BANNER();//打印/* context switch to main task (entry function is _main()) */_nano_fiber_swap();//觸發svc中斷,切換context/*
* Compiler can't tell that the above routines won't return and issues * a warning unless we explicitly tell it that control never gets this * far. */CODE_UNREACHABLE;}
目前已經具備加載內核的條件,這裏便是不同內核加載的分界點,nanokernel與MICROKERNEL都實現了_main函數。
可以通過編譯條件(CONFIG_NANOKERNEL)來選擇使用什麼內核,兩者的區別可以簡單認爲nano是單任務,micro是多任務內核。
在進入內核之前,向總結下都做了啥:
1、關中斷,設置BASEPRI爲默認值(2or3),區別是irq_offload是否支持,這個中斷用於調度,需要CONFIG_IRQ_OFFLOAD支持。
不關中斷則意味着系統需要響應中斷,但是此時初始化系統纔是第一要務,所以關掉中斷。
2、設置PSP爲C函數執行提供條件。C的執行需要一個棧指針來執行存放局部變量和返回指針。
3、設置中斷向量表地址到指定的數據結構。清理bss區。如果是XIP需要將向量表拷貝到ram中。
4、準備進入內核的數據及_main任務的創建。此時只是創建,並未調度。
5、緊要設備初始化,比如debug需要uart口、gpiio口這些基本功能。
6、執行svc,切換到第4步中創建的_main任務,進入內核時代。
參考:
http://www.freebuf.com/articles/system/24177.html
下一篇具體的stm32f4移置過程