前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MIPS架构深入理解3-协处理器0

MIPS架构深入理解3-协处理器0

作者头像
Tupelo
发布2022-08-15 16:13:34
1.2K0
发布2022-08-15 16:13:34
举报
文章被收录于专栏:嵌入式ARM和Linux

1 引言

1.1 什么是协处理器0

前面我们已经对MIPS架构CPU有了粗略的了解。显然,它提供了众多优秀的功能。但是,应用的场景不同,往往需要CPU做的事情也不一样,这就需要必须能够对CPU以及它提供的功能进行有选择的配置。这是协处理器诞生的根本原因。

ARM架构也使用协处理器进行控制,称为协处理器15,(cp15)。

MIPS架构CPU使用协处理器0进行CPU的配置和管理。那么,它到底能够干什么呢?

  • CPU配置
  • Cache控制
  • 异常、中断控制: 中断或异常发生时的行为和处理的定义。
  • 内存管理单元控制
  • 其它工作: 定时器(timer)、事件计数器(event)、奇偶/错误校验。一些与CPU紧密相关,而又不便通过I/O进行访问的功能,都会被添加到协处理器0中进行控制。

1.2 包含的寄存器

对于相关的寄存器,在此,不再详述。使用时,参阅相关的数据手册即可。

2 CPU控制指令

2.1 写CPU控制寄存器的指令

代码语言:javascript
复制
mtc0 s, <n>     # 把数据拷贝到协处理器0

这条指令的作用是把通用寄存器s中的值拷贝到协处理器的寄存器n中,数据位数是32位。大部分的协处理器寄存器是32位的,对于少数的64位协处理器寄存器可以使用dmtc0指令进行操作。这是设置CPU控制寄存器的唯一方法。

32位架构的时候,最多有32个协处理器寄存器。但是MIPS32/64架构扩展到了256个寄存器,为了向前兼容,在指令中添加select域来控制多个寄存器。比如

代码语言:javascript
复制
mtc0 s, $12, 1

select域的值等于1,其作用就是把通用寄存器s的值写入到协处理器的寄存器12组中的编号为1的寄存器中。也就是说,寄存器12可以有多个具体的寄存器,使用select域选择对应的哪个寄存器。

2.2 读取CPU控制寄存器的指令

代码语言:javascript
复制
mfc0 d, $n      # 把协处理器第n个寄存器中的值写入到通用寄存器d中

上述指令的作用是把协处理器0中的第n个寄存器中的内容读取到通用寄存器d中。

2.3 特殊的控制指令eret

所有的架构的CPU在面对特权等级切换的时候(一般就是异常返回时),都会面临一个问题:一方面,在返回用户态程序之前就降低特权等级,那么会立即引发一个异常指令访问的二次异常;另一方面,如果返回到用户程序之后再降低特权等级,那么可能会被恶意程序利用内核态运行某些指令。解决这个问题的办法就是,保证异常返回时的指令是原子操作。MIPS架构的CPU提供了这个指令eret

3 特殊寄存器的使用场景

  1. 上电后:需要设置SR寄存器,使CPU进入一个可工作的状态。
  2. 处理异常: 在异常入口处,不会保存任何程序计数器,只把返回地址存入EPC寄存器中。MIPS架构CPU硬件对于堆栈一无所知,所以发生异常时,无法打印堆栈中的数据。(ARM和X86硬件可以保存堆栈,所以,发生异常时,可以打印堆栈中的关键数据)。对于MIPS架构,程序发生异常时,只能看EPC寄存器中的值,然后通过反汇编得到执行代码的地址,从而获取到导致异常的代码大概位置。充分利用异常发生时的信息,是调试程序的一种有效手段。 MIPS架构也为异常处理程序保留了2个寄存器v0v1。我们的程序可以把一些异常需要的重要信息保存在这儿。但是,通用寄存器极易发生变化,大部分时候,这两个寄存器不建议使用。 可以通过查看Cause寄存器,判断属于哪类异常,从而做相应的处理。
  3. 从异常返回时: 保存返回地址到EPC寄存器中。 不论是何种异常,返回时,都要恢复SR寄存器和特权等级、使能中断并消除异常带来的影响。最后eret指令返回用户程序并复位SR(EXL)寄存器。
  4. 中断: 通过SR寄存器中的中断控制位,可以设置哪些中断具有更高的优先级。虽然,MIPS架构硬件没有提供中断优先级,但是软件可以任意设置。
  5. 一些特殊的指令: 比如系统调用(syscall)和调试断点(break),还有一些CPU实现了一些特殊的指令。

4 CP0协处理器操作时可能发生的问题

我们知道CPU的指令是按照流水线的方式执行。有可能,操作协处理器的指令还没执行彻底,其它指令就已经开始执行了。如何才能保证CP0的操作生效后,再执行相关指令呢?

因为MIPS架构的设计理念是 硬件尽量简单,辅以软件实现。所以,早期的软件开发人员使用nop操作,保证操作协处理器的正确性。但是,这无疑增加了软件开发人员的难度。于是,MIPS32/64架构定义了新的指令:避险指令。

三个避险指令:

  1. ehb指令 消除执行危险。早期的MIPS架构CPU把这个当做一个nop操作。
  2. jr.hb和jalr.hb指令 跳转寄存器指令,用来消除指令危险。最常见的使用方式就是替换普通的子程序返回和子程序调用指令。 旧架构上,这两个指令还是会被解释成jr和jalr指令。在这些CPU上,指令会清除CPU的管道流水线。而且大部分时候,对于不遵守MIPS32/64架构规范的CPU还会提供必要的延时。

4.1 指令危险

指令危险和用户危险通常发生在改变CP0状态的时候(比如,改变某个寄存器、TLB项、或者一个cache行),这会影响我们普通的取值指令(在某些情况下,还会影响load/store指令访问内存的方式)。

我们必须规避这种不可控的风险。在改变CP0操作之后,添加危险屏障指令,消除这种可能产生的不可控的危险。

这类危险都有:

  1. 改变TLB项: 在受影响的内存页上取指、加载和存储数据。
  2. 改变EntryHi寄存器(ASID域) 非全局映射内存区域上的取指、加载和存储数据。
  3. 改变到ERL模式 从kuseg内存区域取指、加载和存储数据。
  4. cache指令改变cache行 在受影响的line上取指、加载和存储数据。
  5. 改变watchpoint寄存器 在匹配的地址上取指、加载和存储数据
  6. 影子寄存器设置发生改变 任何使用通用寄存器的情况(执行危险)
  7. 修改CP0寄存器,禁止中断 仍然能够被中断的指令(异常危险)

它们中大部分都是指令危险,可以使用jr.hbjalr.hb指令避免这种指令危险。

4.2 CP0指令间的危险

mfc0tlbwitlbwrtlbr指令、读取CP0的cache指令以及tlbp指令都依赖于CP0寄存器中的值。所以,这些指令执行时,有可能发生执行危险。为了保证安全,可以在

可以在读取CP0寄存器值的指令之前,添加ehb指令。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式ARM和Linux 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 引言
    • 1.1 什么是协处理器0
      • 1.2 包含的寄存器
      • 2 CPU控制指令
      • 2.1 写CPU控制寄存器的指令
      • 2.2 读取CPU控制寄存器的指令
      • 2.3 特殊的控制指令eret
      • 3 特殊寄存器的使用场景
      • 4 CP0协处理器操作时可能发生的问题
        • 4.1 指令危险
          • 4.2 CP0指令间的危险
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档