日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

optee的栈指针和栈内存的介绍

發布時間:2025/3/21 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 optee的栈指针和栈内存的介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

快速鏈接:
.
👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈


相關推薦:
optee aarch64體系下棧的設計(sp_el0/sp_el1)


注意: 在默認的情況下,本文講述的是armv8 aarch64體系,optee 3.12.0代碼

文章目錄

        • 1、optee os的四種棧內存
        • 2、armv8-aarch64的兩種棧指針
        • 3、optee有關棧內存和棧指針的代碼導讀
          • (1)、在編譯時分配棧空間
          • (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)、在編譯時分配棧空間
  • 在“nozi_stack”section中為每一個Core分配一個stack_tmp空間
  • 在“nozi_stack”section中為每一個Core分配一個stack_abt空間
  • 在“nozi_stack”section中分配CFG_TEE_CORE_NB_CORE數量個stack_thread空間
#define DECLARE_STACK(name, num_stacks, stack_size, linkage) \ linkage uint32_t name[num_stacks] \[ROUNDUP(stack_size + STACK_CANARY_SIZE + STACK_CHECK_EXTRA, \STACK_ALIGNMENT) / sizeof(uint32_t)] \__attribute__((section(".nozi_stack." # name), \aligned(STACK_ALIGNMENT)))#define GET_STACK(stack) ((vaddr_t)(stack) + STACK_SIZE(stack))DECLARE_STACK(stack_tmp, CFG_TEE_CORE_NB_CORE,STACK_TMP_SIZE + CFG_STACK_TMP_EXTRA, static); DECLARE_STACK(stack_abt, CFG_TEE_CORE_NB_CORE, STACK_ABT_SIZE, static); #ifndef CFG_WITH_PAGER DECLARE_STACK(stack_thread, CFG_NUM_THREADS,STACK_THREAD_SIZE + CFG_STACK_THREAD_EXTRA, static); #endif
(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 , :
/* load abt_stack_va_end */ldr x1, [sp, #THREAD_CORE_LOCAL_ABT_STACK_VA_END]/* Keep pointer to initial record in x0 */mov x0, sp/* Switch to SP_EL0 */msr spsel, #0mov sp, x1

總結

以上是生活随笔為你收集整理的optee的栈指针和栈内存的介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。