1. 內核棧的分配,即thread_info的分配,是在do_fork->dup_task_struct中分配(默認為2個pages),並賦值給task_struct->stack;
2. 用戶棧的分配分兩種:
一是pthread create會事先mmap分配好用戶棧,傳給do_fork->copy_thread:用戶棧起始地址會賦值給pt_regs->sp,接着設置內核棧底p->thread.cpu_context.sp = (unsigned long)childregs;
二是fork時,借用了父進程的線程棧,若ret_from_user后應用層調用了exec->do_execuveat_common->exe_binprm->search_binary_handler->load_elf_binary->set_arg_pages,重新分配用戶棧,接着調用start_thread配置pt_regs;
3. 內核態(SVC模式)下的寄存器上下文存放位置:task_struct的thread成員,類型為struct thread_struct;
4. 用戶態(非異常模式)下的寄存器上下文存放位置:內核棧的底部。可如此獲取(task_pt_regs(task_struct)):struct task_struct的stack成員指向struct thread_info,thread_info即為內核棧的起始地址,thread_info+內核棧的固定大小(2 page),即為struct pt_regs的結束地址,pt_regs即為用戶態寄存器上下文的存放位置;
5. thread_info的task成員指向task_struct結構體;
6. 進程切換只會發生在內核態,即進程切換只需要考慮內核態的寄存器上下文切換,見schedule->__schedule->switch_to->cpu_switch_to中,將當前的regs保存到current->thread->context,同時恢復nex taskt的regs;
7. 發生系統調用/異常時,需要保存用戶態/內核態的寄存器上下文,此時通過kernel_entry,將用戶態/內核態的regs保存於異常模式的棧中,當異常完成后,調用kernel_exit,將用戶態/內核態的regs恢復;
綜上,只要知道了task_struct,即可知道內核棧的起始地址(即thread_info=task_struct->stack),也知道了內核態的寄存器上下文(即task_struct->thread->context);同時,也知道了用戶態寄存器上下文(即task_struct->stack+kthread_stack_size-sizeof(pt_regs)),從而知道用戶棧的當前地址(即pt_regs->sp)