基于JOS 80x86 的堆栈切换简要分析

这个问题一直困扰很久,发现还是有点粗心,源头--堆栈初始化没怎么搞明白.

这里首先强调,一定一定要搞清楚分段和分页保护的机制.

现有分段,后有分页,分页可有可无,看寄存器cr0是否开启PE位(page enable. 在JOS系统的boot.S里就已经开启了)

文章从三个方面对栈进行分析

0. GDT 全局段寻址描述表

1. 栈的初始化.

2.用户栈到内核栈的切换

3.内核栈到用户栈的切换

0. GDT 全局段寻址描述表

你能看见第0个段这个时候是不允许访问的,GD_KT右移三位变成 (0x8 >> 3 == 1),第一个段是内核的代码段.可读可执行.第二个是GD_KD 右移三位 (0x10 >> 3 ==  2)第二段.是内核数据段.

第三个GD_UT右移三位(0x18 >> 3 == 3) 第三个段是用户代码段.

第四个GD_UD 右移三位(0x20 >> 3 == 4) 第四个段是用户数据段.

后面的TSS段和我们的主题关系不大,只是任务切换的时候有用.

看过这里之后,嘛嘛再也不用担心别人装逼的时候说"代码和数据是分离的",我听不懂了.

纸老虎!

1.栈的初始化.

首先开机系统开始运行的时候,在boot.S阶段,还没有开启之前,就立马设置好了栈.怎么做的呢?

首先,把ax寄存器异或置0.然后把ax寄存器的值赋值给ds es ss寄存器.

初始的时候,数据段,额外段,堆栈段,都指向第0个段.这时候还没有什么分页机制

段寻址 address == segment : offset == (segment << 4 bits ) + offset 就直接得到物理地址了

而这里选择的是第0个段啊!同志啊,...在这个"原始的荒野",你用的地址都是物理地址

接着立马就开启了分页机制,

lgdt指令马上加载我们之前介绍的GDT全局段描述表.

开启分页机制,我们也就进入了保护模式.

接着在bootloader阶段各种段 ds cs都指向$ PROT_MODE_DSEG 0x10指向的内核数据段

重要的事情说三遍,

JOS中堆栈段和数据段指向同一个段,

JOS中堆栈段和数据段指向同一个段,

JOS中堆栈段和数据段指向同一个段,

: )

到后来初始化CPU的时候,也是把ss指向 GD_KD

OK ,到这里栈的初始化就算讲明白了(至少我自我感觉非常良好哈哈哈)

2. 用户栈切换到内核栈.

这里有各种方式可以切换,我们集中分析一种Trap Gate触发的切换就好了(其余的还有Call Gate, Interrupt Gate,Task Gate)可以去看赵炯的0.11 Linux源代码分析那本书,对于80x86的介绍非常的详细,也可以读Intel的手册...

重点放在*(int *)0xDeadBeef = 0就好,其他的可以无视,和我们这一小节的主题无关,我们关注的是栈的切换.

由于这里尝试对一个非法地址写入,那么直接page fault,有米有! 

由于触发的异常,那么CPU会帮我们直接把堆栈段进行切换(注意,很多其他寄存器不会自动切换,但是cs ss会!)

口说无凭,我们来测试

下面是刚好在这句坑爹的指令执行之前,各种寄存器的状态

常规寄存器都不需要怎么关注,集中看 cs ss ds es fs gd eflags就好

下面我们看对比图.触发page fault前后的对比.

你会发现 cs ss 变了其他的 ds es fs gs都没变,而且这时候 eflags的IF标识没啦,中断这个时候是被屏蔽的.

结论: 触发异常的时候,CPU是会自动切换 代码段和堆栈段寄存器的,而数据段没有自动切换,以至于我们需要手动的在汇编代码中切换 ds .当ds都完成切换的时候,就完成了所谓的从用户态到内核态切换.

3. 内核态到用户态的切换(这里不讨论用户异常栈的情况).

真正切换的地方在这里.从内核栈切换到普通用户栈.实质上是前面用户态到内核态的一个逆向过程.

寄存器pop的顺序都是完全相反的...

这里把tf指针指向的 struct Trapframe设置成栈顶指针,很巧妙的把各种恢复各种寄存器的值.

直到最后 iret由于返回地址不再内核代码段内,发生堆栈切换.

这是切换前后的寄存器对比图:

切换之后,eflags立马有了 IF,允许了中断调用.

时间: 2024-10-16 13:16:24

基于JOS 80x86 的堆栈切换简要分析的相关文章

RxJava &amp;&amp; Agera 从源码简要分析基本调用流程(2)

版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/124 来源:腾云阁 https://www.qcloud.com/community 接上篇RxJava && Agera 从源码简要分析基本调用流程(1)我们从"1.订阅过程"."2.变换过程"进行分析,下篇文章我们继续分析"3.线程切换过程" 3.线程切换过程 从上文中我们知道了R

ARM Linux 大小核切换 ——cortex-A7 big.LITTLE 大小核 切换代码分析

ARM Linux 大小核切换——cortex-A7 big.LITTLE 大小切换代码分析 8核CPU或者是更多核的处理器,这些CPU有可能不完全对称.有的是4个A15和4个A7,或者是4个A57和4个A53,甚至像海思麒麟935处理器(4核A53 2.2 GHz + 4核A53 1.5 GHz),这8个核的频率可能不一样,则使用过程中需要大小核切换(频率高的是大核,频率低的是小核).本文以ARM cortex-A7为例,分析大小核切换的代码,着重于分析实现切换的代码,对于为什么要这样切换.以

Android 4.4 Kitkat 音频实现及简要分析

在 Android 4.4 上实现录放音 背景 Android 自 ICS 开始,音频系统就有了很大的变化,先是抛弃了 alsalib,然后是采用了 AIO,各级框架上,都有了自己的特色,与 Linux 的音频应用渐行渐远,形成了自己独特的音频管理和音频配置功能.总的来说改进还是非常大,至少在用户体验上已经大大的超越了之前的版本.我们就从 4.4 的音频实现上来分析其中的一些变化和实现机制. 要求 首先是硬件功能正常,这个不表. Linux 支持 alsa 驱动,生成 alsa 子系统,最好是能

Android电源管理-休眠简要分析

工作需要,需要对这一块深入学习.故在此做一点分析记录,存疑解惑. 一.开篇 1.Linux 描述的电源状态 - On(on)                                                 S0 -  Working - Standby (standby)                              S1 -  CPU and RAM are powered but not executed - Suspend to RAM(mem)        

Android 5.1 Settings源代码简要分析

转载请注明出处,谢谢~http://blog.csdn.net/u011974987/article/details/51004854. 概述: 先声明:本人工作快两年了,仍是菜鸟级别的.羞愧啊!曾经遇到好多知识点都没有记录下来,感觉挺可惜的.如今有机会接触Android 源代码. 我们一个Android组的搞Setting,我认为是得写得东西.毕竟才接触.如今仅仅能看一段时间代码,就先记录下一些收获吧,说多了就是泪~本文主要针对L平台上Settings模块正常启动流程做一个简要分析,并试着分析

Android 5.0 Settings源码简要分析

概述: 先声明:本人工作快两年了,仍是菜鸟级别的,惭愧啊!以前遇到好多知识点都没有记录下来,感觉挺可惜的,现在有机会接触Android 源码.我们一个Android组的搞Setting,我觉得是得写得东西,毕竟才接触,现在只能看一段时间代码,就先记录下一些收获吧,说多了就是泪~本文主要针对L平台上Settings模块正常启动流程做一个简要分析,并试着分析一下Settings下面某选项的实现. Setting 简介 在之前的KK平台上Settings模块的第一个Activity名字为Setting

Android -- Vold机制简要分析

Android -- Vold机制简要分析 Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SDK的插拔.挂载/卸载和格式化等:它是Android平台外部存储系统的管控枢纽. Vold的整个控制模块主要由三个类模块构成:NetlinkManager.VolumeManager和CommandListener,它们的功能划分大概是: NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息 VolumeManager:管理模块,对Net

uboot源码简要分析

uboot源码简要分析 一.uboot源码整体框架 源码解压以后,我们可以看到以下的文件和文件夹: cpu 与处理器相关的文件.每个子目录中都包括cpu.c和interrupt.c.start.S.u-boot.lds. cpu.c:初始化CPU.设置指令Cache和数据Cache等 interrupt.c:设置系统的各种中断和异常 start.S:是U-boot启动时执行的第一个文件,它主要做最早期的系统初始化,代码重定向和设置系统堆栈,为进入U-boot第二阶段的C程序奠定基础. u-boo

loosejar原理简要分析

loosejar这个小工具可以动态分析出应用中有每个jar包的实际使用情况,详情请参阅<通过loosejar清理应用中冗余的jar包>基本原理是利用instrumentation的特性用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义.有了这样的功能,开发者就可以实现更为灵活的运行时虚拟机监控和 Java 类操作了.关于instrumentation的详细介绍,可以参阅这篇文章&l