Skip navigation.
主页

内核研究

帅云霓 的图片

MIPS体系结构 Q & A Part 0x04 系统异常篇

31.
Q: 异常和中断有什么区别?
A: 中断是异常的一种,占用0号异常。中断是异步发生的,一般由硬件事件触发(如某GPIO引脚的电平跳变),和指令执行阶段无关。而异常是指令触发发生的,也就是同步发生的。

32.
Q: 什么叫“精确异常”?
A: "精确异常" 的原文是precise exception。precise这个词其实有“穷讲究”的意思。在这里指的就是:当异常发生时,已经执行完memory阶段操作的指令均有效,未执行到该阶段的指令,在流水线中一律丢弃。该异常的触发者为该条指令。

33.
Q: 对于TLB miss/Address error这样的异常,实际上为什么不会写入指令中的地址呢?
A: 因为这个时候指令只执行完ALU阶段,还没到Memory,所以被丢弃了。从处理器设计的角度来看,这种非法指令本身也不该生效。

34.
Q: 发生异常的时候,是不是会进入内核态?
A: 是的。当然如果原本就在内核态,那么还是会在内核态。一般来说,操作系统通用的进入内核,是通过一条syscall指令,产生类型为0x08的异常来实现的。

35.
Q: 我想知道,breakpoint, syscall和trap三种异常都是特殊指令触发的,它们有什么区别?
A: 一般说来,syscall指令是用于一般性的系统调用进入内核,类似于x86的调用门。
breakpoint是程序错误处理,例如,mips的除法指令,如果除数为0,会造成不确定的结果。编译器在对除法表达式进行处理的时候,就做一个判断,如果除数为0,则执行指令:break 0x07。如果运行时出现了除以0,那么,break 0x07这条指令会抛出一个breakpoint异常,子类型为0x07——这样,程序员在debug的时候看见这个异常信息,就可以判断,程序中除数出现了0。

帅云霓 的图片

MIPS体系结构 Q & A Part 0x03 CP0篇

20.
Q: CP0是干嘛的?
A: CP0是协处理器0,Co-Processor 0的缩写,MIPS最多可以支持4个协处理器,其中CP0是强制要求实现的,用于处理器的状态控制等。它包括MMU、异常控制、Cache控制等功能。

21.
Q: MIPS的其他协处理器都有什么呢?
A: 这个和具体厂商的实现有关系了。CP1是浮点协处理器,是可选的,CP2和CP3是厂家自定义的。

22.
Q: CP0里面都有哪些寄存器?一般用在什么场合?
A: CP0有32个寄存器,一般操作系统的内核才会接触到它们。主要有MMU类、异常控制类、断点控制类等。

23.
Q: 这几类寄存器各有哪些呢?
A: MMU相关的,有Index,Random, EntryLo0, EntryLo1, Context, EntryHi, MageMask和Wirds几个。具体用途介绍MMU的时候会提到。
异常控制相关的有Status, Cause, EPC, BadVaddr等。
断点控制的有Count, Compare, WatchLo, WatchHi等。
此外,还有PRId,用于确定CPU的类型;
LLAddr, 用于原子锁指令;
Config, 用于配置处理器。

24.
Q: 对CP0寄存器如何访问呢?
A: 有专门的指令访问。32bit读:
mfc0 rs, /*Move from co-processor 0*/
64bit读:
dmfc0 rs, /*Double move from co-processor 0*/
32bit写:
mtc0 rs, /*Move to co-processor 0*/
64bit写:
dmtc0 rs, /*Double move to co-processor 0*/

25.
Q: 对于CP0寄存器,如果只想修改其中的几个bit,该怎样做?
A: 只能先读取到GPR中,修改后写回。
如:
mfc0 t0, SR
nop
and t0, BIT_MASK_ALPHA
or t0, BIT_MASK_BETA
mtc0 t0, SR
nop

26.
Q: 为什么要在mfc和mtc后面插入一个nop指令?
A: 这是为了避免CP0 hazard,简单地说就是执行完mfc或mtc指令之后,有可能要等待一条指令的时间,数据才真正读取或写入到寄存器之中,在这个过程中如果修改相应寄存器会导致错误的结果。

27.
Q: 为什么会有hazard现象?

帅云霓 的图片

MIPS体系结构 Q & A Part 0x02 地址空间

11.
Q: MIPS的内存空间有多大?
A: 在32-bit模式下是4GB,用户态可以使用的空间是2GB。

12.
Q: 用户态是使用哪部分内存?
A: 虚拟地址0x00000000-0x7fffffff的2GB,叫做user space, mapped & cached.

13.
Q: 什么是用户态,还有哪些别的状态呢?
A: MIPS除了用户态还有内核态,在内核态下可以访问全部资源,但用户态只能访问部分,如CP0、MMU等,用户态是不可以访问的。

14.
Q: 那么,怎样从用户态进入内核态呢?
A: 一般的正常渠道是执行syscall指令。另外还有trap/brackpoint等指令,会引发相应的异常,进入内核态。当然程序错误引起的异常(如非对齐地址访问、未映射的地址访问)也会引发异常,进入内核态。

15.
Q: 在内核态下可以访问多大的内存空间呢?
A: 4GB,但是从0x80000000到0xBFFFFFFF有特殊用途。0x80000000到0x9FFFFFFF,和0xA0000000到0xBFFFFFFF这两段地址,硬件上指向同一段物理地址,0x00000000到0x1fffffff。

16.
Q: 为什么要这样做?
A: 0xA0000000到0xBFFFFFFF是不经过Cache访问的,可以保证在上电时就可用,并且,作为硬件IO寄存器映射地址时,不会被cache 扰乱。MIPS的上电启动地址,0xBFC00000就在这段内存中。而0x80000000到0x9FFFFFFF这段地址是经过Cache映射的,内核代码段和堆栈往往放在这一段内存,以保证访问和执行速度。

17.
Q: 我的硬件工程师将bootrom连接到总线的0xBFC00000地址了,为什么系统不能启动?
A: 0xBFC00000是逻辑地址(程序中的地址),对应的物理地址(将逻辑分析仪连接在总线上,捕捉到的地址)是0x1FC00000。

18.
Q: 那么,0xC0000000到0xFFFFFFFF的地址空间是干嘛的?
A: 可以作为内核使用的内存,比如kmalloc之类的函数分配使用。这段内存是通过MMU和TLB映射的。

19.

帅云霓 的图片

MIPS体系结构 Q & A Part 0x01 寄存器与内存访问

最近问我MIPS体系结构相关问题的人越来越多,在这里小结一下。
一般在职业有段者水平的MIPS体系结构问题,都能在这里找到答案。

1.
Q: MIPS有多少一般用途的寄存器?
A: 32个。

2.
Q: 我在看反汇编代码的时候,看到一些寄存器名叫zero, a1, a2...还有sp, ra这样的名字。为什么给他们起这些名字呢?
A: MIPS的通用寄存器中,按照编译器的通常的约定,某些寄存器是做专门用途的,比如sp就是堆栈指针,ra是函数调用的返回地址等等。当然你也可以不按照这些约定编程,例如用$2存放堆栈指针,$3存放返回地址,但这样的程序,和标准库链接就不能工作了。

3.
Q: 为什么MIPS的SP寄存器也是通用寄存器呢?而且MIPS似乎没有专门的压栈/出栈指令啊。
A: 这是MIPS这样的RISC处理器,同x86为代表的CISC处理器的重大区别之一。RISC没有专门的硬件实现的堆栈寄存器/指令,改为软件实现,在函数入口堆栈指针递减,堆栈向低地址生长,返回处恢复堆栈值,销毁堆栈帧。

4.
Q: MIPS的堆栈用软件实现,那么,MIPS的函数调用开销会更大吗?
A: 这是x86为首的CISC支持者,经常诟病RISC的一点。但是,实际上,我们知道,MIPS使用了4个GPR(一般用途寄存器)来传递前4个Word的函数参数,而x86只有EAX一个寄存器用于传递函数参数。所以,如果函数的参数小于或等于4个word,那就不需要使用栈。我们知道,大多数函数的参数都在4 个word以内。——所以,这一点不比太担心。另外,写太多参数的函数时,建议使用结构体传递这些参数。

5.
Q: MIPS的lh, lb这样的指令,会改变寄存器里的前2个/1个字节,还是后2个/1个字节?
A:一般来说是低位。

6.
Q: MIPS是大端(Big-endian)的,还是小端的(Little-endian)?

droplet 的图片

understanding linux network internals 第六部分: 邻居子系统 [连载]

to be added

droplet 的图片

understanding linux network internals 第五部分:ipv4 [连载]

to be added

droplet 的图片

understanding linux network internals 第四部分:桥 [连载]

第14章 桥:基本概念
在讲述桥的第一个章节中,我们将看到:桥是什么,如何使用它,以及桥的使用限制等。我会着重描述透明桥,地址学习,以及转发数据库的使用。在本章中,我会解释为什么桥不能在有环路的拓扑中使用,而在下一章中,我们会看到生成树(STP)协议如何解决这个问题。当然,还有很多其他类型的桥,不过它们很少被用到,而且linux内核也没有实现它们。
本章所使用的网络拓扑并不代表真实的网络环境,它们只是按教学的要求而绘制的演示拓扑。

droplet 的图片

understanding linux network internals 第三部分: 发送与接收 [连载]

第三部分:发送与接收

本部分用五章的篇幅来描述内核中网络报文的流动路径,以及各功能模块如何作用于此网络报文,你将会对网络协议栈有一个总体的印象。你将会了解每个子系统的功能,以及它们在协议栈中的位置。在这一部分,我们不描述网络路由(有专门的章节描述这个话题);我们也不描述防火墙功能,因为它已超出了本书所讲述的范围。

术语发送通常用于描述任意方向上的通讯。但是在内核中,发送只用于表示向外发送数据帧,与之对应的,接收指从外部收到数据帧。在某些地方,我也会用ingress表示接收,egress表示发送。

在两台主机之间转发网络报文同样涉及到接收和发送过程。在第10章中,我会描述一些转发的话题,在第五部分和第七部分,我会详细描述它。

在第一章中,我们已经了解了术语帧,数据报,网络报文之间的区别。由于在第三部分中,我们主要讨论的是L2和L3之间的接口,所以术语帧和网络报文在大部分情况下是相等的。尽管大部分时间,我都使用术语帧,但是某些时候,我也会使用术语网络报文来表示哪些没有引用特定协议层信息的数据包。在讨论代码时,我经常使用术语网络报文。

下面是我们将会在第三部分中看到的内容

第九章:中断和网络设备驱动

在本章中,你将会了解软中断处理程序和内核同步机制。

第十章:网络帧接收

本章描述l2如何接收一个网络帧。

第十一章:网络帧发送

本章描述l2如果发送一个网络帧。

第十二章:中断相关的信息

本章收集了前面章节中描述的与中断相关的信息。

第十三章:协议处理程序

droplet 的图片

ipid is not increased when sending packet on some linux platform

在某些linux平台上,往外发包时,ipid不会递增,导致某些依赖于ipid的程序无法执行。我试过用DGRAM往外发udp包时发现的这个问题。
能够工作的版本:
Linux localhost.localdomain 2.6.9-34.ELsmp #1 SMP Fri Feb 24 16:54:53 EST 2006 i686 i686 i386 GNU/Linux
不能工作的版本
Linux localhost.localdomain 2.6.9-55.EL #1 Fri Apr 20 16:35:59 EDT 2007 i686 i686 i386 GNU/Linux
Linux localhost.localdomain 2.6.9-42.ELsmp #1 SMP Wed Jul 12 23:27:17 EDT 2006 i686 i686 i386 GNU/Linux
这可能是改某个bug而引入的新bug,可能这个漏洞相关。有时间再过来自己看看。
http://en.wikipedia.org/wiki/Idle_scan

帅云霓 的图片

深入浅出MIPS 四 MIPS的异常与中断 (Section 1)

MIPS的异常和中断,同其他体系结构,例如Intel的IA32架构下的中断/调用门/陷阱机制类似,其目的主要有三:
一,提供一个合法地从用户态到内核态的切换通道,使得程序能够访问如CP0、KSeg等平时被保护的资源;
二,处理一些非法的操作,如TLB Miss/Address Error等;
三,处理外部和内部的中断。与IA32架构区别的是,所有的中断均来自0号Exception。

《See MIPS Run》中,将MIPS的异常机制称为“精确异常”。用通俗的语言解释之,由于异常是执行指令时同步发生,因此,在造成异常的指令之前执行的指令,无疑均是有效的。然而,由于MIPS的高度流水体系结构,在引发异常的指令执行时,后面一条指令已经完成了读取和译码的预备工作,万事俱备,只待ALU部件空闲即执行之。当异常产生时,这些预备工作便被废弃。CPU从异常中返回时,再重新做读取和译码的工作。
因此,我们就可以保证,在异常发生时,异常指令之后所有的指令均不会被执行。这样,就不需要在MIPS的异常处理例程(Exception Handler)中为延迟槽(Delay Slot)指令而烦恼了。

MIPS的异常类型,在前文中已经有所提及。为了方便读者阅读,先再次给出一个概览,然后再详解一些常见的异常。
MIPS异常类型总共有:
0: Interrupt,中断;
1: TLB Modified,试图修改TLB中映射为只读的内存地址;
2: TLB Miss Load,试图读取一个没有在TLB中映射到物理地址的虚拟地址;
3: TLB Miss Store,试图向一个没有在TLB中映射到物理地址的虚拟地址存入数据;
4: Address Error Load,试图从一个非对齐的地址读取信息;
5: Address Error Store,试图向一个非对齐的地址写入信息;
6: Instruction Bus Error,一般是指令Cache出错;
7: Data Bus Error,一般是数据Cache出错;
8: Syscall,由syscall指令产生。操作系统下,通用的由用户态进入内核态的方法。可以类比IA32的“调用门”理解;
9: Break Point,由break指令产生。最常见的bp指令,是由编译器产生的,在除法运算时插入一个break point指令,以达到在除0时抛出错误信息的目的。因此,如果在定位问题时发现了一个Break Point异常,且它的异常分代码为07,应当考虑是出现了除0的情形;
10: RI,保留指令。在CPU执行到一条没有定义的指令时,进入此异常;
11: Co-processor Unavilible,协处理器不可用。这个异常是由于试图对不存在的协处理器进行操作引起的。特别的,在没有浮点协处理器的处理器上执行这条命令,会导致这个异常。随之,操作系统会调用模拟浮点的lib库,来实现软件的浮点运算;
12: Overflow,算术溢出。只有带符号的运算会引起这个异常;
13: Trap,这个异常来源于trap指令。和syscall指令类似地,trap指令也会引起一个异常,但trap指令可以附带一些条件,这样可以用于调试程序用。
14: VCEI,指令高速缓存中的虚地址一致性错误。(没明白怎么回事,还有待高手补充)
15: Float Point Exception,浮点异常;
16: Co-processor 2 Exception,协处理器2的异常;
17~22,留作将来的扩展;
23: Watch,内存断点异常。当设定了WatchLo/WatchHi两个寄存器时起作用。当load/store的虚拟地址和WatchLo/WatchHi中匹配时,会引发这样一个异常;/* 这个地方经典著作《See MIPS Run》犯了一个错误,将虚拟地址写成了物理地址 */
24~30,留作将来的扩展;

Syndicate content