Chinaunix首页 | 论坛 | 博客
  • 博客访问: 123173
  • 博文数量: 31
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 361
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-11 15:38
文章分类

全部博文(31)

文章存档

2008年(31)

我的朋友

分类: LINUX

2008-04-19 11:49:27

      以前我在看关于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使用的是自己栈(在任务1task_struct中的tss中指出)。而任务0仍然使用之前使用的栈作为它的用户栈。

3)  用户态栈

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

4)  核心态栈

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

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

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

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

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

三、任务0中的栈切换

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

 

阅读(1762) | 评论(0) | 转发(0) |
0

上一篇:Linux初时化过程

下一篇:Linux系统调用

给主人留下些什么吧!~~