Linux中的栈

copy from http://blog.csdn.net/chenglian_999/article/details/4785720

以前我在看关于Linux原理的内容的时候,总遇到什么内核栈、用户栈。今天单独的看了一下Linux中栈的使用,在这里作一下总结。

一、linux中的堆栈

      Linux0.11核中总共涉及到了四种栈:系统引导时候的临时栈;内核初始化使用的栈;内核态栈;用户态栈。

1)  系统引导时候的临时栈

在boosetct中,当它把自身移动到0x90000处时候,就会设置临时栈,以0x90000为段地址,0xff00为偏移地址。

Setup中也沿用了这个栈,作为系统引导的临时栈。

2) 内核初始化使用的栈

在进入保护模式执行head的时候,栈的段地址设置在内核的数据段地址处(此时ss中保存的不再是具体的基地址了,而是堆栈段选择符,当然也是数据段的选择符),栈顶指针指向user_stack数组顶端,保留一页内存作为堆栈。

在进入main进行系统初始化的时候,沿用head中设置的栈,但在move_to_user_mode()之后,代码的执行切换到了任务0,在任务0中用创建了任务1,任务1使用的是自己栈(在任务1的task_struct中的tss中指出)。而任务0仍然使用之前使用的栈作为它的用户栈。

3)  用户态栈

当用户进程在运行的时候,会涉及到过程调用等栈操作,此时它用的是用户栈,用户栈的基地址是任务的数据段基地址,栈顶指针在靠近线性地址空间的顶端处(只是靠近顶端,最顶端存放的是命令行参数和环境变量)。它使用的实际物理页是在“写时复制”时分配的得到的。

4)  核心态栈

当用户进程执行内核代码的时候,例如系统调用,就会使用核心态栈,每个任务都有自己的核心态栈,它的物理位置处在此任务的task_struct所在页中,具体的基地址和栈顶指针由tss中的ss0和esp0指定。

二、用户态栈和内核态栈的切换

执行任务切换的时候,毫无疑问会发生栈的切换,它使用的堆栈会发生变化,它的切换是两个任务的用户栈间的切换,是通过TSS完成的;而当CPU的特权级发生变化的时候,它使用的堆栈也会发生变化,而这时的切换是同一任务的用户栈和核心栈的切换。下面我就说一下用户态栈和核心态栈的切换的大致过程。

在0.11核中所有的中断都属于内核代码,所以如果一个中断产生时,任务正运行用户代码,也就是运行在用户态,那么就会引起任务从用户态(特权级3)向内核态(特权级0)的转变,此时就会发生从用户态栈到核心态栈的切换。CPU先从task_struct中的TSS中获得内核态栈的地址,然后把用户态栈的段地址、栈顶指针压入核心态栈,随后再把eflags、es、ip也压入堆栈。接着执行中断处理程序,此时使用的是内核态栈。执行完中断处理程序返回的时候,iret会返回到用户模式,恢复用户栈和eflags。这样就又使用用户栈。

注释:如果处在内核态,中断的时候,cpu并不进行ss、esp的栈操作。

三、任务0中的栈切换

    在内核初时话过程中,会将代码的执行交给任务0(move_to_user_mode),任务0的内核栈在它自己的任务数据结构所在页面的末端,而任务0的用户栈是之前CPU进入保护模式时候用的栈,即usr_stack[],把它设置为任务0的用户栈是利用手工设置的:当执行iret的时候,如果发生了特权级的变化,iret还要把栈中的栈基址和栈顶指针也同时恢复,那么在move_to_user_mode()中,LINUX手工地把任务0的用户栈的基址和栈顶指针压入堆栈,同时把任务0的eflag、cs、ip压入堆栈,注意此时压入的SS,CS虽然也指向模式转换之前的段,但是它门包括了特权级的信息,所以当cs出栈的时候,发现它的特权级(3)与现在的(0)不同,而且低于现在的,所以就会还会再把新栈的SS和esp出来。这样代码的执行就交给了处在用户模式下的任务0,在任务0中再创建任务1.......


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值