optee内核中栈的介绍(二)
快速鏈接:
.
👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈
相關推薦:
1、optee的棧指針和棧內存的介紹
2、optee aarch64體系下棧的設計(sp_el0/sp_el1)
文章目錄
- 1、在optee中的棧內存:
- 2、optee中的棧指針
- 3、在不同階段使用不同的棧內存和棧指針
- 3、開機時對所有棧的初始化
- 4、init_thread_stacks 將thread stack地址寫入到thread結構體的變量中
- 5、thread結構體的變量中的棧地址寫入到sp寄存器中
- 6、abt/tmp stack
1、在optee中的棧內存:
- Secure monitor stack (128 bytes),綁定cpu, 給armv7使用的
- Temp stack (small ~1KB) 128,綁定cpu, 狀態切換時使用的, 使用該棧時interrupt是關閉的
- Abort stack (medium ~2KB),綁定cpu, 取數據或取指令異常時,使用這個棧.
如果是user發生的abort,那么kill掉TA,如果是kernel發生的abort,那么kernel可能會掛掉 - Thread stack (large ~8KB) 給進程使用的
(1)、aarch32/aarch64各個棧內存size的定義
#ifdef CFG_WITH_ARM_TRUSTED_FW #define STACK_TMP_OFFS 0 #else #define STACK_TMP_OFFS SM_STACK_TMP_RESERVE_SIZE //Secure monitor stack #endif#ifdef ARM32 #ifdef CFG_CORE_SANITIZE_KADDRESS #define STACK_TMP_SIZE (3072 + STACK_TMP_OFFS) #else #define STACK_TMP_SIZE (1536 + STACK_TMP_OFFS) //Temp stack #endif #define STACK_THREAD_SIZE 8192 // Thread stack#ifdef CFG_CORE_SANITIZE_KADDRESS #define STACK_ABT_SIZE 3072 #else #define STACK_ABT_SIZE 2048 //Abort stack #endif#endif /*ARM32*/#ifdef ARM64 #define STACK_TMP_SIZE (2048 + STACK_TMP_OFFS) //Temp stack #define STACK_THREAD_SIZE 8192 // Thread stack#if TRACE_LEVEL > 0 #define STACK_ABT_SIZE 3072 //Abort stack #else #define STACK_ABT_SIZE 1024 #endif #endif /*ARM64*/struct thread_ctx threads[CFG_NUM_THREADS]; //optee中的thread slot(2)、棧內存的定義
其實就是在".nozi_stack"的section段定義一些數組. 通過數組定義可以發現tmp、abt是和cpu core綁定的.thread_stack是和線程綁定的
2、optee中的棧指針
armv7-A/aarch32
temp stack : SP_SVC、SP_IRQ、SP_FIQ
abort : use sp_abt
thread : use sp_svc
armv8-a/aarch64
只有兩個棧指針:sp_el1、sp_el0
3、在不同階段使用不同的棧內存和棧指針
(1)、在optee啟動時到第一次回到normal world,使用的是temp stack,棧指針是sp_svc
(2)、當cpu從REE回來時,如果是fast call,則使用temp stack
如果是std call,將切換到thread slot 的棧中. 當std call執行完成了,再切回temp stack
(3)、當發生RPC調用時thread_rpc(…),也回切回到temp stack,直到從normal再回來.
(4)、當foriegin中斷發生時,類似于RPC調用
aarch64
只有兩個棧指針:sp_el1、sp_el0
當有exception進來,先使用sp_el1,再分配sp_el0
切換sp_el0時,spsel要配置成0
3、開機時對所有棧的初始化
在init_canaries()函數中,其實就是往棧首棧尾分別寫入0xdededede和0xabababab
static void init_canaries(void) { #ifdef CFG_WITH_STACK_CANARIESsize_t n; #define INIT_CANARY(name) \for (n = 0; n < ARRAY_SIZE(name); n++) { \uint32_t *start_canary = &GET_START_CANARY(name, n); \uint32_t *end_canary = &GET_END_CANARY(name, n); \\*start_canary = START_CANARY_VALUE; \*end_canary = END_CANARY_VALUE; \FMSG("#Stack canaries for %s[%zu] with top at %p\n", \#name, n, (void *)(end_canary - 1)); \FMSG("watch *%p\n", (void *)end_canary); \}INIT_CANARY(stack_tmp);INIT_CANARY(stack_abt); #ifndef CFG_WITH_PAGER //我們是沒有定義這個的INIT_CANARY(stack_thread); #endif #endif/*CFG_WITH_STACK_CANARIES*/ }#define START_CANARY_VALUE 0xdededede #define END_CANARY_VALUE 0xabababab4、init_thread_stacks 將thread stack地址寫入到thread結構體的變量中
其實就是讓當前進程結構體中的threads[thread_id].stack_va_end變量,指向當前進程對應的thread stack的數組
sp – GET_STACK(stack_thread[n]) – 指向當前進程對應的thread stack的數組
threads[thread_id].stack_va_end – 當前進程的結構體的變量
5、thread結構體的變量中的棧地址寫入到sp寄存器中
thread->regs.sp = thread->stack_va_end;
#ifdef ARM32 static void init_regs(struct thread_ctx *thread,struct thread_smc_args *args) {thread->regs.pc = (uint32_t)thread_std_smc_entry;/** Stdcalls starts in SVC mode with masked foreign interrupts, masked* Asynchronous abort and unmasked native interrupts.*/thread->regs.cpsr = read_cpsr() & ARM32_CPSR_E;thread->regs.cpsr |= CPSR_MODE_SVC | CPSR_A |(THREAD_EXCP_FOREIGN_INTR << ARM32_CPSR_F_SHIFT);/* Enable thumb mode if it's a thumb instruction */if (thread->regs.pc & 1)thread->regs.cpsr |= CPSR_T;/* Reinitialize stack pointer */thread->regs.svc_sp = thread->stack_va_end;/** Copy arguments into context. This will make the* arguments appear in r0-r7 when thread is started.*/thread->regs.r0 = args->a0;thread->regs.r1 = args->a1;thread->regs.r2 = args->a2;thread->regs.r3 = args->a3;thread->regs.r4 = args->a4;thread->regs.r5 = args->a5;thread->regs.r6 = args->a6;thread->regs.r7 = args->a7; } #endif /*ARM32*/ #ifdef ARM64 static void init_regs(struct thread_ctx *thread,struct thread_smc_args *args) {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] = args->a0;thread->regs.x[1] = args->a1;thread->regs.x[2] = args->a2;thread->regs.x[3] = args->a3;thread->regs.x[4] = args->a4;thread->regs.x[5] = args->a5;thread->regs.x[6] = args->a6;thread->regs.x[7] = args->a7;/* Set up frame pointer as per the Aarch64 AAPCS */thread->regs.x[29] = 0; } #endif /*ARM64*/6、abt/tmp stack
在thread_init_per_cpu()來將棧地址寫入到sp寄存器
void thread_init_per_cpu(void) {size_t pos = get_core_pos();struct thread_core_local *l = thread_get_core_local();init_sec_mon(pos);set_tmp_stack(l, GET_STACK(stack_tmp[pos]) - STACK_TMP_OFFS);set_abt_stack(l, GET_STACK(stack_abt[pos]));thread_init_vbar(get_excp_vect()); }aarch32在調用set_tmp_stack()/set_abt_stack()時就已經將棧地址寫入到sp寄存器了
#ifdef ARM32 static void set_tmp_stack(struct thread_core_local *l, vaddr_t sp) {l->tmp_stack_va_end = sp;thread_set_irq_sp(sp);thread_set_fiq_sp(sp); }static void set_abt_stack(struct thread_core_local *l, vaddr_t sp) {l->abt_stack_va_end = sp;thread_set_abt_sp((vaddr_t)l);thread_set_und_sp((vaddr_t)l); } #endif /*ARM32*/將abt stack地址寫入到sp_abt
FUNC thread_set_abt_sp , : UNWIND( .fnstart) UNWIND( .cantunwind)mrs r1, cpsr //先保存cpsrcps #CPSR_MODE_ABT //切回到abt modemov sp, r0 //將abt stack地址寫入到sp_abtmsr cpsr, r1 //回復cpsrbx lr UNWIND( .fnend) END_FUNC thread_set_abt_sp也就是設置棧地址時,伴隨著模式切換
aarch32在調用set_tmp_stack()/set_abt_stack()時只是將棧地址寫入到了l->tmp_stack_va_end和l->abt_stack_va_end變量
#ifdef ARM64 static void set_tmp_stack(struct thread_core_local *l, vaddr_t sp) {/** We're already using the tmp stack when this function is called* so there's no need to assign it to any stack pointer. However,* we'll need to restore it at different times so store it here.*/l->tmp_stack_va_end = sp; }static void set_abt_stack(struct thread_core_local *l, vaddr_t sp) {l->abt_stack_va_end = sp; } #endif /*ARM64*/在std進來時,獲取tmp stack,然后寫入到sp
bl thread_get_tmp_sp
mov sp, x0
在rpc調用時,同樣如此
bl thread_get_tmp_sp
mov sp, x0 /* Switch to tmp stack */
總結
以上是生活随笔為你收集整理的optee内核中栈的介绍(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [工具]-脚本自动化工具:按照linux
- 下一篇: [hypervisor]-AArch64