免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: sherf
打印 上一主题 下一主题

请教:进程表与TSS关系 [复制链接]

论坛徽章:
0
31 [报告]
发表于 2008-10-30 18:05 |只看该作者
等待ing

论坛徽章:
0
32 [报告]
发表于 2008-10-30 18:55 |只看该作者
等待ing

论坛徽章:
0
33 [报告]
发表于 2008-10-30 20:07 |只看该作者

yhb04,在吗?

等待ing

论坛徽章:
0
34 [报告]
发表于 2008-10-30 20:21 |只看该作者
有人会吗?

论坛徽章:
0
35 [报告]
发表于 2008-10-30 20:29 |只看该作者
原帖由 yhb04 于 2008-10-28 19:15 发表
INTEL的设计者使用TSS的本意是方便操作系统进行进程切换,他们的初衷是每一个进程对应一个TSS,那么进程切换可以(大部分)由硬件自动完成,这也是为什么TSS为几乎所有的CPU寄存器都预留了位置。
但是LINUX并没 ...


你知道的好多啊!学习了!

论坛徽章:
0
36 [报告]
发表于 2008-10-30 21:10 |只看该作者
yhb04,

回去仔细回想和查阅了一些资料之后,仍有一些不是很清晰:

1、在进程A(CPL=0)-> 进程B(CPL=3)时,即ring 0 -> ring 3,
  对于进程B,在切换过程中,堆栈也在切换,具体是“调度模块”->B的内核栈(ring0)->B的用户栈(ring3)。
  问题:
  在B的堆栈切换过程中需不需要使用到TSS?如果需要,那在当初初始化TSS的时候,是不是要初始化SS0,ESP0,SS1,ESP1?如果不需要,那还需不需要进行栈切换?如果不需要进行栈切换,那是不是A和B共用一个栈段(在这里因为是A->B,因此共用的是A的栈段)?如果需要进行栈切换,那SS和ESP的值是不是直接从进程表得到的?

2、在进程A(CPL=3)-> 进程B(CPL=0)时,即ring 3 -> ring 0,
  对于进程B,在切换过程中,堆栈也在切换,具体是“调度模块”->B的内核栈(ring0)。
  问题:
  在B的堆栈切换过程中需不需要使用到TSS?如果需要,那在当初初始化TSS的时候,是不是只要初始化SS0,ESP0就行?如果需要设置SS0,那是把SS0设置成指向A的内核栈(ring 0)还是指向B的内核栈(ring 0)?

3、内核栈和用户栈的理解
假定以下场景:
M:进程调度模块(CPL=0),并假定是一个汇编程序(如:schedule.asm)
A:用户进程(CPL=3),并假定是一个汇编程序(如:user_a.asm)

在实现M调度A时(ring 0 -> ring 3):
对于M,需在程序schedule.asm中定义一个堆栈段,而这个堆栈段就称为调度程序使用的内核栈
对于A,假定特权级为0,1,2,3在系统中都有用到(有的只是对应0,3),则在程序user_a.asm中应定义4个堆栈段,其中对应特权级为0的是用户进程内核栈,对应特权级为1,2,3的3个堆栈段则称为用户栈

以上对内核栈和用户栈的理解对吗?

[ 本帖最后由 sherf 于 2008-10-30 21:23 编辑 ]

论坛徽章:
0
37 [报告]
发表于 2008-10-30 21:31 |只看该作者
有人知道吗?

论坛徽章:
0
38 [报告]
发表于 2008-10-30 21:43 |只看该作者
原帖由 sherf 于 2008-10-30 21:10 发表
yhb04,

回去仔细回想和查阅了一些资料之后,仍有一些不是很清晰:

1、在进程A(CPL=0)-> 进程B(CPL=3)时,即ring 0 -> ring 3,
  对于进程B,在切换过程中,堆栈也在切换,具体是“调度模块”->B的内 ...


1、在进程A(CPL=0)-> 进程B(CPL=3)时,即ring 0 -> ring 3,
  对于进程B,在切换过程中,堆栈也在切换,具体是“调度模块”->B的内核栈(ring0)->B的用户栈(ring3)。
  问题:
  在B的堆栈切换过程中需不需要使用到TSS?如果需要,那在当初初始化TSS的时候,是不是要初始化SS0,ESP0,SS1,ESP1?

你指的是那一次堆栈切换?
有2种切换 ,都不会使用TSS中的ESP。
1.B从内核态返回用户态需要从内核堆栈切换回用户堆栈
  这种情形下不会使用TSS。CPU 只有从低特级权到高特级权转换时才会使用到TSS中的堆栈值(比如从Ring3-->Ring0),当CPU从高特级权转换回低特级权时,不会用到TSS中堆栈值(比如从Ring0-->Ring3)。
  这是因为当CPU从低特级权转换到高特级权时(比如从用户态转换到内核态),CPU会自动把用户堆栈值(ss和esp)保存到内核堆栈中,所以当进程从内核态准备返回用户态时(执行汇编指令 iret),CPU会将事先保存在内核栈的用户堆栈值恢复。
2.从A的内核栈切换到B的内核栈,也不会使用TSS中esp,但是会更新TSS中的esp0值。

唯一会“使用”到TSS中的esp值的时候是从用户态转换到(陷入)内核态,需要内核栈的初始值(空栈)。




2、在进程A(CPL=3)-> 进程B(CPL=0)时,即ring 3 -> ring 0,
  对于进程B,在切换过程中,堆栈也在切换,具体是“调度模块”->B的内核栈(ring0)。
  问题:
  在B的堆栈切换过程中需不需要使用到TSS?如果需要,那在当初初始化TSS的时候,是不是只要初始化SS0,ESP0就行?

在内核态执行调度A-->B,注意进程A和B现在都处在内核态,而且它们的内核堆栈都是非空的(保存了一些进程上下文),在A切换到B之前,内核(进程调度模块)一直在使用A的内核栈,在即将切换到B的内核栈之前,内核(进程调度模块)将当前A的内核栈指针(即CPU中的当前esp值)保存到A的进程描述表中,以便下次重新调度到A时切换到A内核栈时作为A内核栈的值。同理,内核(进程调度模块)根据B的进程描述表中的相应esp值(上次保存的)作为B的内核栈初始值。
这里要跟TSS中的esp0撇清关系,TSS中的esp0表示的时某个进程的内核栈为空时的esp值,与之相反,每个进程描述表中的esp值是进程被夺走CPU时的内核栈指针(肯定是非空的!)。
事实上每个进程描述表中有esp0的域,每次进程重新获得CPU时(被调度模块选中),调度模块将TSS中的esp0更新为描述表中esp0值。
TSS中的esp0每次发生进程调度时都会被更新,因为每个进程都有属于自己的内核栈,TSS都会被更新为当前进程的空内核栈时的值。


3、内核栈和用户栈的理解
假定以下场景:
M:进程调度模块(CPL=0),并假定是一个汇编程序(如:schedule.asm)
A:用户进程(CPL=3),并假定是一个汇编程序(如:user_a.asm)

在实现M调度A时(ring 0 -> ring 3):
对于M,需在程序schedule.asm中定义一个堆栈段,而这个堆栈段就称为调度程序使用的内核栈
对于A,假定特权级为0,1,2,3在系统中都有用到(有的只是对应0,3),则在程序user_a.asm中应定义4个堆栈段,其中对应特权级为0的是用户进程内核栈,对应特权级为1,2,3的3个堆栈段则称为用户栈

你的说法(M自己使用堆栈)在某些操作系统内核中可能是对的,但是在现在的Linux中,(在一般的配置中)没有所谓的内核自己的堆栈,进程调度模块作为内核映像的一部分,只使用到那当前(正在CPU上运行)的进程的内核栈。

[ 本帖最后由 yhb04 于 2008-10-30 21:47 编辑 ]

论坛徽章:
0
39 [报告]
发表于 2008-10-30 21:50 |只看该作者
to sherf:

在这里问得这么辛苦,既然这样偶详细给你说清楚:

当进程发生权限改变的切换时,也就发生 stack 切换,如:ring 3 -> ring 0,则 stack 的切换操作具体是:

1、processor 从 TR 处获 TSS 块
  (1) 当前的 SS 和 esp 临时保存起来。(tmp_ss 和 tmp_sp)
  (2) 从 TSS 获取相应权限的 stack 指令(SS 和 esp),装入 ss 入 esp 中
    (3) tmp_ss 和 tmp_sp 入栈 (旧的 ss 及 sp,即 ring3 的 stack 指针)
   (4) cs 和 eip 入栈(旧的 cs 及 eip,即 ring3 的指令指针)
   (5) 此时,已经调整到 ring0 级的 stack了

以上是个具体操作过程,当然在此之前要经过 权限检查!


2、stack 切换回原来的: ring0 -> ring3
  (1) old cs 和 eip 出栈,装入 cs 及 eip
  (2) ss 和 esp 出栈, 装入 ss 及 esp
    (3) 当前的 ss 值和 esp 抛弃
  (4) 此时,切换回原来的 stack,ring3 级。

同样,以上都要经过权限检查。
  

论坛徽章:
0
40 [报告]
发表于 2008-10-30 22:37 |只看该作者
yhb04,mik :

谢谢两位的详细回复。

yhb04,

我对你回复理解如下:
对于1、在进程A(CPL=0)-> 进程B(CPL=3)时,即ring 0 -> ring 3,有以下2种情况,
1)B从内核态返回用户态需要从内核堆栈切换回用户堆栈
2)从A的内核栈切换到B的内核栈
这两种情况下都需要栈切换,但都不会用到TSS,只会从当前用户进程的内核栈中将SS和ESP恢复以实现栈切换。

对于2、在A-->B时,
1)A和B的内核栈指针都会被保存到进程表里面作为以后再调用/恢复时的初始值(因为内核栈指针非空)。
2)TSS的ESP0是每次都被缺省指向进程内核栈为空时的值,但当进程获得CPU时会被更新成进程表中的ESP值(即1中提到内核指针值)。

对于3、我有点不明白,因为如果进程调度模块要进行堆栈操作时,难道它使用的也是用户进程的内核栈?


另外,对上面的问题我还有些疑问和个人的一些理解:
1、既然ring0->ring3 不需要使用TSS,为什么ring3 -> ring0要使用TSS(直接重复向1中的操作不行吗?)?
2、从上面2来看,进程切换似乎只解决了如何获得 esp0 的值,而没有提到进程如何获得 esp3 (这里 esp3 指的是用户堆栈指针)。我想如果要切换至用户进程,肯定也要一起切换至用户堆栈吧。那到底如何获得这个 esp3 呢?

3、我的一些理解
假设以下场景:
M:进程调度模块(CPL=0)
A:用户进程1(CPL=3)
B:用户进程2(CPL=3)
C:用户进程3(CPL=0)

如果 A->B,则必须经过以下过程:
1)A(ring 3) -> A(ring 0)
2)A(ring 0) -> M(ring 0)
3)M(ring 0) -> B(ring 0)
4)B(ring 0) -> B(ring 3)

其中,
对于1),就是常说的 ring 3-> ring 0,而且从这可以判断出 "ring 3->ring 0"必定是对同一进程而言(比如说1)里面指的就是用户进程A,ring0和ring3则只是指A的两种运行状态)。就像如果存在A->C,虽然看上去也是从特权级3->特权级0,但这个不是指我们常说的"ring 3-> ring 0"。而堆栈的切换是从 “进程A的用户栈”切换至“进程A的内核栈”。esp0的获取:esp0<-TSS.esp0<-进程表中的esp域。
对于2),属于进程调度模块对进程A的操作。会发生堆栈切换吗?还是说堆栈操作仅仅对A的内核栈的操作而言。
对于3),属于进程调度模块对进程B的操作。会发生堆栈切换吗?还是说堆栈操作仅仅对B的内核栈的操作而言。
对于4),与1)类似,就是常说的 ring 0-> ring 3 。而堆栈的切换是从“进程B的内核栈”切换至“进程B的用户栈”。esp3的获取:未知?

在这4点中,只有1)用到TSS,而且 esp0 的值指的是”用户进程A“在 ring0 状态下(即内核栈)的堆栈入口指针。

不知道我的理解对不对?

[ 本帖最后由 sherf 于 2008-10-30 23:22 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP