找回密码
 立即注册
搜索
热搜: 活动 通知
查看: 2022|回复: 11

x86汇编第二版第十七章协同任务切换里特权栈信息保存的问题

[复制链接]

3

主题

33

回帖

381

积分

至尊会员

积分
381

至尊会员

发表于 2024-4-12 22:09:15 | 显示全部楼层 |阅读模式
老师,在x86汇编第二版第十七章协同任务切换里,用户程序通过call gate调用InitTaskSwitch内核例程的时候,需要切换特权栈(从3换到0),然后:
1. 用户栈段(3)的SS和ESP被压入特权0栈段
2. 用户程序CS和EIP也被压入特权0栈段
3. InitTaskSwitch内核例程里切换到另一个任务(比如内核任务),处理器会把当前任务(用户程序内核态)信息存入该任务的TSS里
4. 其中TSS里偏移56的地方存入了ESP(这个ESP应该是用户程序的0特权栈的ESP吧)
5. 等再次切回到用户任务(此时还是用户程序内核态)时,从TSS里恢复号特权栈SS0和ESP0
6. 继续在InitTaskSwitch内核例程(用户程序内核态)里往下执行
7. 在retf时,因涉及特权切换(0特权栈里压入的用户程序CS选择子里RPL=3),所以要切换回用户CPL=3的栈段
8. 从0特权栈里找到前面1里压入的用户程序特权等级3的SS和ESP
9. 回到用户程序继续执行,此时栈段是特权等级3的SS

不知道我上面的理解是否正确?
即,用户程序通过调用门发起任务切换时会涉及特权级切换,栈段也要切换,在这种情况下,用户程序特权级3的SS和ESP没有保存在TSS里,而是在TSS里保存特权0的ESP,但是可以通过特权0的SS和ESP找回保存在里面的用户程序特权3的SS和ESP



416

主题

315

回帖

3288

积分

管理员

积分
3288
发表于 2024-4-13 13:58:12 | 显示全部楼层
基本正确。
另,不在TSS里设置SS3和ESP3的原因是,在任何时候都不存在从高特权级到3特权级的控制转移(除了调用门或者中断返回)。

3

主题

33

回帖

381

积分

至尊会员

积分
381

至尊会员

 楼主| 发表于 2024-4-13 21:22:47 | 显示全部楼层
站长 发表于 2024-4-13 13:58
基本正确。
另,不在TSS里设置SS3和ESP3的原因是,在任何时候都不存在从高特权级到3特权级的控制转移(除了 ...

还有个问题,在第18章抢占式多任务里,假设1153行放开中断之后发生0x70中断,引起任务切换:
1. 在413行切换到用户程序执行
2. 此时用户程序的eflags状态应该是从TSS里读取
3. 用户TSS里elfags是在901和902行设置的(用的是当时内核执行到load_relocate例程时的eflags状态)
4. 用户程序运行时,通过0x70中断切换回内核任务执行

我的疑问是:
1. 用户程序运行时能触发0x70中断,那么当时elfags的IF应该是1,
2. 而用户程序里eflags的最早来源应该是前面901和902行里内核load_relocate例程设置的
3. 但是进入load_relocate例程前1143行关闭了中断,即eflags的IF位是0
4. 那么进入load_relocate例程后设置用户TSS里存储的eflags位IF也应该是0
5. 照这样推演,等413行第一次切换到用户程序时,用户程序应该处于中断关闭的状态,那为什么还有0x70中断呢?

416

主题

315

回帖

3288

积分

管理员

积分
3288
发表于 2024-4-14 13:16:55 | 显示全部楼层
时间一长我也记不清了。应该是低特权级下不能改变IF吧。我们都再查查。

3

主题

33

回帖

381

积分

至尊会员

积分
381

至尊会员

 楼主| 发表于 2024-4-15 00:22:04 | 显示全部楼层
站长 发表于 2024-4-14 13:16
时间一长我也记不清了。应该是低特权级下不能改变IF吧。我们都再查查。

这一部分是内核(特权0)1143行开始创立用户程序任务, 这里通过cli指令,IF位(内核的eflags)为0
  1. cli
复制代码
进入load_relocate_program例程后,901行和902行把当前的eflags圧栈再弹出到用户任务TSS,这样存入用户任务TSS的的eflags里IF位应该为0.....
  1. <blockquote>         pushfd
复制代码
等到发生0x70中断切换到用户任务时,TSS中取出的eflags里IF位就还是0了。。。目前就是这里我没想通

3

主题

33

回帖

381

积分

至尊会员

积分
381

至尊会员

 楼主| 发表于 2024-4-15 14:12:17 | 显示全部楼层
站长 发表于 2024-4-14 13:16
时间一长我也记不清了。应该是低特权级下不能改变IF吧。我们都再查查。

我用bochs跟踪调试了一下,发现一些奇怪的情况

---------------------------------------------------------------
上图里我跟踪进用户任务,发现eflags里的if位的确是0.....,所以此时应该没法触发中断切换任务

------------------------------------------------------------------
截图上传说超过限制了,我只好打文字了
继续执行.....

但是继续调试,让用户任务调用一次put_string,输出“,,,,,,,”返回用户任务后,eflags里if位又变成了1.......
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
猜想:
现在我大概想明白了,按照老师书里的程序,的确进入用户任务的时候eflags里if值为0,中断禁止(来自内核pushf在pop进用户tss里的设置)。
但是用户任务后面会通过调用门调用内核公共例程put_string,而这里有cli和sti指令,所以说等返回到用户任务时,if位变成了1,后续就可以触发RTC中断切换任务啦~

---------------------------------------------------------------------------------------------------------------------------------------------------------------------
最后验证:
我修改了用户程序,把put_string调用注释掉,结果进入用户任务后,就卡死在无限循环里了,因为此时if=0,无法触发RTC中断
  1. .do_prn:
  2.          mov ebx,message_1
  3.          ;call far [fs:PrintString]
  4.          jmp .do_prn      
复制代码




416

主题

315

回帖

3288

积分

管理员

积分
3288
发表于 2024-4-15 14:27:41 | 显示全部楼层
cindeequan 发表于 2024-4-15 14:12
我用bochs跟踪调试了一下,发现一些奇怪的情况

----------------------------------------------------- ...

那就说明是我当初没有考虑周全。不过最令我印象深刻的还是你这种探究精神,值得所有人学习。值得大大地称赞!

3

主题

33

回帖

381

积分

至尊会员

积分
381

至尊会员

 楼主| 发表于 2024-4-15 22:05:08 | 显示全部楼层
站长 发表于 2024-4-15 14:27
那就说明是我当初没有考虑周全。不过最令我印象深刻的还是你这种探究精神,值得所有人学习。值得大大地称 ...

谢谢老师,我看书里第20章的程序里把put_string例程调整了
开头用了
pushfd
cli
.....
返回前用了
popfd
这样就防止了在put_string里不小心把if位修改了

另外load_relocate前也不使用cli了,而是把append_tcb移到了load_reloacte外。
这样也跑通了

416

主题

315

回帖

3288

积分

管理员

积分
3288
发表于 2024-4-16 09:58:57 | 显示全部楼层
cindeequan 发表于 2024-4-15 22:05
谢谢老师,我看书里第20章的程序里把put_string例程调整了
开头用了
pushfd

或者在pushfd之后添加修改压栈内容的IF位的指令,然后再pop到TSS。

3

主题

33

回帖

381

积分

至尊会员

积分
381

至尊会员

 楼主| 发表于 2024-4-17 17:56:59 | 显示全部楼层
站长 发表于 2024-4-16 09:58
或者在pushfd之后添加修改压栈内容的IF位的指令,然后再pop到TSS。

我看C19和C20里内核代码设置8259A从片级联的代码是
  1.          mov al,0x11
  2.          out 0xa0,al                        ;ICW1:边沿触发/级联方式
  3.          mov al,0x70
  4.          out 0xa1,al                        ;ICW2:起始中断向量
  5. <b><i><u>         mov al,0x04</u></i></b>

  6.          out 0xa1,al                        ;ICW3:从片级联到IR2
  7.          mov al,0x01
  8.          out 0xa1,al                        ;ICW4:非总线缓冲,全嵌套,正常EOI
复制代码
这里ICW3设置的04 我看的资料里应该指的是主片的IRQ4引脚(老师推荐的《车子小姐8259A》)
但是bochs跑会报错,提示PIC = 4 未启用


我查了下C18的内核代码里ICW3设置的是2,意思主片IRQ2引脚(我理解这才是正确设置,因为主片设置里是IRQ2引脚接入从片)
  1.          mov al,0x11
  2.          out 0xa0,al                        ;ICW1:边沿触发/级联方式
  3.          mov al,0x70
  4.          out 0xa1,al                        ;ICW2:起始中断向量
  5. <u><i><b>mov al,0x02</b></i></u>
  6.          out 0xa1,al                        ;ICW3:从片级联到IR2
  7.          mov al,0x01
  8.          out 0xa1,al                        ;ICW4:非总线缓冲,全嵌套,正常EOI
复制代码

这样bochs就不会报错了


问题1:
C18和C19,C20不同的ICW3是笔误?还是另有考虑?

问题2:
不管ICW3是2还是4,C20的程序我在Vbox里跑都能跑起来,但是都有一定概率报严重错误,也就是有时候能一直无限循环切换任务,有时候能正常启动,但是在内核->app1->app2之后,再切回内核的时候就会报严重错误,这是啥情况呢。。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|鼠侠网 ( 吉ICP备19001332号 )

GMT+8, 2024-12-22 09:10 , Processed in 0.243841 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表