Linux栈的使用

 以前我在看关于 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、付费专栏及课程。

余额充值