optee的栈指针和栈内存的介绍
快速鏈接:
.
👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈
相關推薦:
optee aarch64體系下棧的設計(sp_el0/sp_el1)
注意: 在默認的情況下,本文講述的是armv8 aarch64體系,optee 3.12.0代碼
文章目錄
- 1、optee os的四種棧內存
- 2、armv8-aarch64的兩種棧指針
- 3、optee有關棧內存和棧指針的代碼導讀
- (1)、在編譯時分配??臻g
- (2)、在boot時和cpu_on時,設置SP_EL0指向tmp_stack,sp_el1指向thread_core_local[pos]
- (3)、normal_entry和normal_exit時,ATF負責保存和恢復SP_EL0/SP_EL1的值
- (4)、在進入optee的thread線程時,會設置SP_EL0指向thread_stack
- (5)、在el1_sync_abort和el0_sync_abort時,會將SP_EL0指向abort_stack
1、optee os的四種棧內存
在學習棧之前,我們先回顧下,optee有兩種進入方式、三種退出方式:
- Boot
- Normal entry
- Normal exit
- RPC exit
- Foreign interrupt exit
然后我們再看下,optee os種定義的四種棧內存,如果是armv8架構,只要看后面三種:
- Secure monitor stack (128 bytes), 綁定CPU,armv7平臺,optee os開啟了secure monitor時,會使用該棧
- Temp stack (small ~1KB),綁定CPU,臨時使用的棧,使用該棧期間,所有中斷都是disabled的,如果有abort那也是fatal的。例如在boot時,會使用temp stack,直至boot完成并退出; normal entry時,也會先使用temp stack,然后再切換程thread stack;
- Abort stack (medium ~2KB),綁定CPU, data abort或pre-fetch abort的時候使用該棧
- Thread stack (large ~8KB),不綁定CPU,給當前線程或任務使用的,使用該棧時,interrupts是打開的
2、armv8-aarch64的兩種棧指針
如果是armv7/aarch32:
- temp stack:在entry和exit時,SP_SVC指向該棧內存。SP_IRQ和SP_FIQ也會指向該棧內存
- abort stack:SP_ABT指向該棧內存
- thread stack:SP_SVC指向該棧內存
如果是armv8 aarch64,ARM有兩種棧指針SP_EL0和SP_EL1。
在進入optee時,硬件上會自動選擇SP_EL1做為SP,SP_EL1指向一個少量空間的結構體thread_core_local[cpu_id]。
隨后會切換到我們常說的棧,也就是SP_EL0
- temp stack:在boot時,SP_EL0指向該棧內存
- abort stack:SP_EL0指向該棧內存
- thread stack:SP_EL0指向該棧內存
透過事務看本質,這里總結一下棧內存和棧指針的使用:
- 在boot的時候、normal entry和normal exit的時候,使用temp stack棧內存,棧指針為SP_EL0
- 在進程正常運行的時候,使用thread stack,棧指針為SP_EL0
- 在abort程序運行的時候,使用abort stack,棧指針為SP_EL0
- 在normal entry剛進入的時候,先使用的是SP_EL1,指向的是thread_core_local[cpu_id]結構體,隨后就會切換到SP_EL0(指向的 temp stack),后面如果再調用到具體的線程,則會使用SP_EL0(指向的 thread stack)
3、optee有關棧內存和棧指針的代碼導讀
(1)、在編譯時分配??臻g
- 在“nozi_stack”section中為每一個Core分配一個stack_tmp空間
- 在“nozi_stack”section中為每一個Core分配一個stack_abt空間
- 在“nozi_stack”section中分配CFG_TEE_CORE_NB_CORE數量個stack_thread空間
(2)、在boot時和cpu_on時,設置SP_EL0指向tmp_stack,sp_el1指向thread_core_local[pos]
在optee的bootup流程中,或在cpu的喚醒流程中,都會調用set_sp函數,進行設置SP_EL0指向tmp_stack,sp_el1指向thread_core_local[pos]結構體
- FUNC _start , :
- FUNC cpu_on_handler
set_sp函數原型
/** Setup SP_EL0 and SPEL1, SP will be set to SP_EL0.* SP_EL0 is assigned stack_tmp_export + cpu_id * stack_tmp_stride* SP_EL1 is assigned thread_core_local[cpu_id]*/.macro set_spbl __get_core_poscmp x0, #CFG_TEE_CORE_NB_CORE/* Unsupported CPU, park it before it breaks something */bge unhandled_cpuadr x1, stack_tmp_strideldr w1, [x1]mul x1, x0, x1adrp x0, stack_tmp_exportadd x0, x0, :lo12:stack_tmp_exportldr x0, [x0]msr spsel, #0add sp, x1, x0bl thread_get_core_localmsr spsel, #1mov sp, x0msr spsel, #0.endm(3)、normal_entry和normal_exit時,ATF負責保存和恢復SP_EL0/SP_EL1的值
(4)、在進入optee的thread線程時,會設置SP_EL0指向thread_stack
如下列代碼中所示,在thread_alloc_and_run中,調用init_regs,該函數中填充了thread->regs.sp = thread->stack_va_end,返回到thread_alloc_and_run函數后,調用thread_resume(&threads[n].regs),將thread_stack的地址,真正寫入到SP_EL0
#ifdef ARM64 static void init_regs(struct thread_ctx *thread, uint32_t a0, uint32_t a1,uint32_t a2, uint32_t a3) {thread->regs.pc = (uint64_t)thread_std_smc_entry;/** Stdcalls starts in SVC mode with masked foreign interrupts, masked* Asynchronous abort and unmasked native interrupts.*/thread->regs.cpsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0,THREAD_EXCP_FOREIGN_INTR | DAIFBIT_ABT);/* Reinitialize stack pointer */thread->regs.sp = thread->stack_va_end;/** Copy arguments into context. This will make the* arguments appear in x0-x7 when thread is started.*/thread->regs.x[0] = a0;thread->regs.x[1] = a1;thread->regs.x[2] = a2;thread->regs.x[3] = a3;thread->regs.x[4] = 0;thread->regs.x[5] = 0;thread->regs.x[6] = 0;thread->regs.x[7] = 0;/* Set up frame pointer as per the Aarch64 AAPCS */thread->regs.x[29] = 0; } #endif /*ARM64*/void thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3) {size_t n;struct thread_core_local *l = thread_get_core_local();bool found_thread = false;assert(l->curr_thread == -1);thread_lock_global();for (n = 0; n < CFG_NUM_THREADS; n++) {if (threads[n].state == THREAD_STATE_FREE) {threads[n].state = THREAD_STATE_ACTIVE;found_thread = true;break;}}thread_unlock_global();if (!found_thread)return;l->curr_thread = n;threads[n].flags = 0;init_regs(threads + n, a0, a1, a2, a3);thread_lazy_save_ns_vfp();l->flags &= ~THREAD_CLF_TMP;thread_resume(&threads[n].regs);/*NOTREACHED*/panic(); }(5)、在el1_sync_abort和el0_sync_abort時,會將SP_EL0指向abort_stack
- LOCAL_FUNC el1_sync_abort , :
- LOCAL_FUNC el0_sync_abort , :
總結
以上是生活随笔為你收集整理的optee的栈指针和栈内存的介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android keymaster的介绍
- 下一篇: optee的Share Memory介绍