日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

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

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

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


相關(guān)推薦:
optee aarch64體系下棧的設(shè)計(sp_el0/sp_el1)


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

文章目錄

        • 1、optee os的四種棧內(nèi)存
        • 2、armv8-aarch64的兩種棧指針
        • 3、optee有關(guān)棧內(nèi)存和棧指針的代碼導(dǎo)讀
          • (1)、在編譯時分配棧空間
          • (2)、在boot時和cpu_on時,設(shè)置SP_EL0指向tmp_stack,sp_el1指向thread_core_local[pos]
          • (3)、normal_entry和normal_exit時,ATF負(fù)責(zé)保存和恢復(fù)SP_EL0/SP_EL1的值
          • (4)、在進(jìn)入optee的thread線程時,會設(shè)置SP_EL0指向thread_stack
          • (5)、在el1_sync_abort和el0_sync_abort時,會將SP_EL0指向abort_stack

1、optee os的四種棧內(nèi)存

在學(xué)習(xí)棧之前,我們先回顧下,optee有兩種進(jìn)入方式、三種退出方式:

  • Boot
  • Normal entry
  • Normal exit
  • RPC exit
  • Foreign interrupt exit

然后我們再看下,optee os種定義的四種棧內(nèi)存,如果是armv8架構(gòu),只要看后面三種:

  • 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,給當(dāng)前線程或任務(wù)使用的,使用該棧時,interrupts是打開的

2、armv8-aarch64的兩種棧指針

如果是armv7/aarch32:

  • temp stack:在entry和exit時,SP_SVC指向該棧內(nèi)存。SP_IRQ和SP_FIQ也會指向該棧內(nèi)存
  • abort stack:SP_ABT指向該棧內(nèi)存
  • thread stack:SP_SVC指向該棧內(nèi)存

如果是armv8 aarch64,ARM有兩種棧指針SP_EL0和SP_EL1。
在進(jìn)入optee時,硬件上會自動選擇SP_EL1做為SP,SP_EL1指向一個少量空間的結(jié)構(gòu)體thread_core_local[cpu_id]。
隨后會切換到我們常說的棧,也就是SP_EL0

  • temp stack:在boot時,SP_EL0指向該棧內(nèi)存
  • abort stack:SP_EL0指向該棧內(nèi)存
  • thread stack:SP_EL0指向該棧內(nèi)存

透過事務(wù)看本質(zhì),這里總結(jié)一下棧內(nèi)存和棧指針的使用:

  • 在boot的時候、normal entry和normal exit的時候,使用temp stack棧內(nèi)存,棧指針為SP_EL0
  • 在進(jìn)程正常運(yùn)行的時候,使用thread stack,棧指針為SP_EL0
  • 在abort程序運(yùn)行的時候,使用abort stack,棧指針為SP_EL0
  • 在normal entry剛進(jìn)入的時候,先使用的是SP_EL1,指向的是thread_core_local[cpu_id]結(jié)構(gòu)體,隨后就會切換到SP_EL0(指向的 temp stack),后面如果再調(diào)用到具體的線程,則會使用SP_EL0(指向的 thread stack)

3、optee有關(guān)棧內(nèi)存和棧指針的代碼導(dǎo)讀

(1)、在編譯時分配棧空間
  • 在“nozi_stack”section中為每一個Core分配一個stack_tmp空間
  • 在“nozi_stack”section中為每一個Core分配一個stack_abt空間
  • 在“nozi_stack”section中分配CFG_TEE_CORE_NB_CORE數(shù)量個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時,設(shè)置SP_EL0指向tmp_stack,sp_el1指向thread_core_local[pos]

在optee的bootup流程中,或在cpu的喚醒流程中,都會調(diào)用set_sp函數(shù),進(jìn)行設(shè)置SP_EL0指向tmp_stack,sp_el1指向thread_core_local[pos]結(jié)構(gòu)體

  • FUNC _start , :
  • FUNC cpu_on_handler

set_sp函數(shù)原型

/** 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負(fù)責(zé)保存和恢復(fù)SP_EL0/SP_EL1的值
(4)、在進(jìn)入optee的thread線程時,會設(shè)置SP_EL0指向thread_stack

如下列代碼中所示,在thread_alloc_and_run中,調(diào)用init_regs,該函數(shù)中填充了thread->regs.sp = thread->stack_va_end,返回到thread_alloc_and_run函數(shù)后,調(diào)用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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。