免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
41 [报告]
发表于 2008-10-30 23:31 |只看该作者
原帖由 sherf 于 2008-10-30 22:37 发表
yhb04,mik :

谢谢两位的详细回复。

yhb04,

我对你回复理解如下:
对于1、在进程A(CPL=0)-> 进程B(CPL=3)时,即ring 0 -> ring 3,有以下2种情况,
1)B从内核态返回用户态需要从内核堆栈切换回用 ...

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

是的,进程调度模块也是内核的部分,从A的内核栈切换到B的内核栈,这部分代码是用汇编写的;对于一般的C函数调用,必须使用堆栈,这是C函数编写者没法控制的,所以在切换堆栈中,使用汇编具体地德控制堆栈。这部分很难讲的清楚。你可以理解为:进程调度模块调度A-->B过程可以分为3部分:1.切换A的内核栈到B的内核栈之前,这时可以安全的使用C函数,因为堆栈是固定的(A的内核栈),2.切换A的内核栈到B的内核栈:需要非常小心,因为堆栈要发生变化,一般的C代码无法控制,所以使用汇编, 3.切换到B的内核栈之后,跟1相同,可以放心使用C代码。


另外,对上面的问题我还有些疑问:
1)既然ring0->ring3 不需要使用TSS,为什么ring3 -> ring0要使用TSS(直接重复向1中的操作不行吗?)?

你似乎没读懂我以前的解释,Mik也已经讲的很彻底了。
通俗的讲,高特级权可以知道低特级权的堆栈地址,因为它的特级权比较高高,这是安全的,就像内核可以完全控制整个系统。相反,让低特技权知道高特级权的信息(比如高特级权的堆栈地址等)是很危险的。所以用户态是无法知道内核态堆栈的,只有通过CPU的特殊机制(陷入)完成。

2)从上面2来看,进程切换似乎只解决了如何获得 esp0 的值,而没有提到进程如何获得 esp3 (这里 esp3 指的是用户堆栈指针)。我想如果要切换至用户进程,肯定也要一起切换至用户堆栈吧。那到底如何获得这个 esp3 呢

这个前面已经说过了,用户进程的堆栈值(你所说的esp3事先已经保存在内核栈中了,返回用户态之前会根据保存的用户户堆栈值恢复堆栈。

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

对于你回复的最后一点,即
2)从上面2来看,进程切换似乎只解决了如何获得 esp0 的值,而没有提到进程如何获得 esp3 (这里 esp3 指的是用户堆栈指针)。我想如果要切换至用户进程,肯定也要一起切换至用户堆栈吧。那到底如何获得这个 esp3 呢

这个前面已经说过了,用户进程的堆栈值(你所说的esp3事先已经保存在内核栈中了,返回用户态之前会根据保存的用户户堆栈值恢复堆栈。
...................................................................

那如果是这样的话,在进程调度模块调度进程B的时候,我想顺序应该是:M(RING0)-> B(RING0),B(RING0)->B(RING3),那如果进程表里面保存的是esp3,那esp0从何而来?
或许我的问题描述的未必很清楚,那我想我先说说我目前的理解(这是后来我在上一贴里面补充的):

假设以下场景:
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 状态下(即内核栈)的堆栈入口指针。

不知道我的理解对不对?

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

对于你回复的最后一点,即
2)从上面2来看,进程切换似乎只解决了如何获得 esp0 的值,而没有提到进程如何获得 esp3 (这里 esp3 指的是用户堆栈指针)。我想如果要切换至用户进程,肯定也要一起切换 ...

那如果是这样的话,在进程调度模块调度进程B的时候,我想顺序应该是:M(RING0)-> B(RING0),B(RING0)->B(RING3),那如果进程表里面保存的是esp3,那esp0从何而来?
或许我的问题描述的未必很清楚,那我想我先说说我目前的理解(这是后来我在上一贴里面补充的):

假设以下场景:
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)

上面的转换有问题,内核(包括进程调度模块M)是进程的仆从(内核是进程的仆从,但是它有比用户进程大的多的权利,很像天朝的人民公仆),所以M是以进程A或B的名义在运行,所以A(Ring0)=M(Ring0)
所以
1)A(Ring3)->A(Ring0)
2)A(Ring0)->B(Ring0)
3)B(Ring0)->B(Ring3)




其中,
对于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的获取:未知?

你的2)不存在,M一直在用A的内核栈
你的3)实际行是A(Ring0)->B(Ring0),就是在这个阶段进行内核堆栈切换。
你的4)从B的内核态返回用户态,用户态堆栈信息在B的内核栈中,由 iret指令自动完成切换。

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

没错。

论坛徽章:
0
44 [报告]
发表于 2008-10-31 00:23 |只看该作者
yhb04,

你的2)不存在,M一直在用A的内核栈
你的3)实际行是A(Ring0)->B(Ring0),就是在这个阶段进行内核堆栈切换。
你的4)从B的内核态返回用户态,用户态堆栈信息在B的内核栈中,由 iret指令自动完成切换。

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

没错。

..............................................................................................

按照你所说的,在3)中A(ring0)->B(ring0),如果进程表里面存放的有关B的esp域是指 esp3 的话,那B的 esp0从何而来?

论坛徽章:
0
45 [报告]
发表于 2008-10-31 00:34 |只看该作者
原帖由 sherf 于 2008-10-31 00:23 发表
yhb04,

你的2)不存在,M一直在用A的内核栈
你的3)实际行是A(Ring0)->B(Ring0),就是在这个阶段进行内核堆栈切换。
你的4)从B的内核态返回用户态,用户态堆栈信息在B的内核栈中,由 iret指令自动完成切换 ...


在进程描述表task_struct结构中(X86 32位)
task_struct{
  ..
struct thread_struct
..
}
结构thread_struct中有如下2个yu:
unsigned long sp0;
unsigned long sp;
其中sp0就是内核栈的初始值,进程调度中使用它更新TSS中的esp0值。
sp保存被调度时该进程的内核栈值。调度模块使用它切换到该进程的内核栈。

论坛徽章:
0
46 [报告]
发表于 2008-10-31 00:45 |只看该作者
yhb04,

哦,这样。

怪不得,我看的是于渊的书,里面的进程表只有一个 esp 域(里面的进程例子是模仿MINIX的)。

谢谢,这么晚了还给我回帖子。

另外,问一句,于渊的书你看过吗?在里面进程部分,像之前的问题(esp3的获取)该如何理解?

最后,还是得再说声“谢谢”!回头我得问问斑竹该如何给分。

论坛徽章:
0
47 [报告]
发表于 2008-10-31 01:06 |只看该作者
原帖由 sherf 于 2008-10-31 00:45 发表
yhb04,

哦,这样。

怪不得,我看的是于渊的书,里面的进程表只有一个 esp 域(里面的进程例子是模仿MINIX的)。

谢谢,这么晚了还给我回帖子。

另外,问一句,于渊的书你看过吗?在里面进程部分, ...

汗,看你的思路很像MINIX3的内核对堆栈的处理,其实我一直很想问你你在看哪本书。
它对堆栈的处理也没错。于渊的书我看过,对于动手方面很不错。他的书在很多方面借鉴了Minix3中的代码。Minix3的内核对于进程(和堆栈)跟LINUX有很大的不同。我以为你来这里问问题,是读LINUX内核的问题。
不同的操作系统对进程(以及堆栈)的处理是很不同的,我上面所说的仅仅是针对目前LINUX内核。

于渊的书也仅仅适用动手,至于深入的读代码,如果是MInix3可以看(中文名叫 塔南鲍姆, Minix的编写者)编写的操作系统教材。它里面对堆栈的处理跟于渊的书很相似(事实上是于渊借鉴它的代码写的)。很不错的书。

论坛徽章:
0
48 [报告]
发表于 2008-10-31 02:20 |只看该作者
yhb04,

有好的 minix 论坛可以推荐吗?

论坛徽章:
0
49 [报告]
发表于 2009-08-25 21:45 |只看该作者

娃哈哈

为虾米我都看不懂??
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP