内核中栈的管理情况如上,stack->pt_regs指向保存的用户态栈信息(task_pt_regs获取)。thread保存的是内核栈的信息。
task_struct数据结构中的stack成员指向thread_union结构(Linux内核通过thread_union联合体来表示进程的内核栈)
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};
但其实thread_struct包含了两部分的栈信息,
struct thread_struct {
/* Cached TLS descriptors: */
struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
unsigned long sp0;
unsigned long sp;
sp0指向了用户态栈
sp指向内核态栈
#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.sp0 - 1)
struct pt_regs {
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long bp;
unsigned long bx;
/* arguments: non interrupts/non tracing syscalls only save up to here*/
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long ax;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long orig_ax;
/* end of arguments */
/* cpu exception frame or undefined */
unsigned long ip;
unsigned long cs;
unsigned long flags;
unsigned long sp;
unsigned long ss;
/* top of stack page */
};
x86本身设计了自带的tss任务切换方式,管理特权进程的切换。但linux系统采用了新的软件机制。摒弃了大部分tss的用途,设计出了以cpu为基准的tss特权切换方式。每个cpu实现一个tss,当特权切换发生时,大部分寄存器采用软件实现的方式保存和调用。
硬件支持实现软件使用中断触发硬件行为, 但摒弃的tss机制只在cpu上使用了。进程权限切换使用软件实现,且只使用了esp0、io bitmap。
但是固定cpu不一定会永远持有 进程栈状态。所以他的tss状态esp0恢复的可能并不一定是当前进程的栈信息。原因在与多任务机制的存在,当任务切换发生的时候,进程状态会被暂停并保存。进而转到另外的任务,tss段将发生变化,所以当任务恢复的时候,tss必须恢复到当前任务的状态。