Bochs源码分析-CPU类
因为学习需要,要看虚拟机Bochs的源代码。写随笔主要为了学习总结,其次是分享大家共同研究,大神勿喷,欢迎评论。
手头资料:bochs源代码,下于:bochs.sourceforge.net,还有喻强写的源码分析电纸书。
在Bochs模拟机里面CPU类是最复杂的一个类,也是最重要的一个类。原因很简单,在整个计算机体系中CPU处于中心位置,计算机其它部件都是在CPU的调控下进行有序的工作,当然CPU如何去和其它部件打交道,也和当时处理的指令有关系。在CPU/cpu.h中申请了很多变量,主要有:通用寄存器如:EAX,EBX,ECX,EDX,EBP,ESI,EDI,ESP作为一些运算的临时变量,各种状态寄存器:flags,段寄存器,TR,GDTR,IDTR,LDTR,IP等为了保存CPU的运行状态如:运行的何地(IP),运行于那个进程(LDTR),发生过什么操作(flags),缓冲寄存器cache,TLB,用于存储一些常用的指令和页表等。在CPU类中的一个主体函数是cpu_loop(),来模拟CPU的工作。函数结构很清晰,分为三个部分,1:异步事件是处理,2取得指令并解析指令。3:执行相应的指令函数。异步事件处理模拟计算机系统的各种中断,大体思想是,在执行一条指令期间可能遇到一些指令异常或者硬件异常或者外部设备的中断请求,会分别设置相应的flags标志位,当CPU结束当前指令会查询flags标志位,先处理相应的异常或中断,然后再继续指令的循环。对于取指令,要和内存类mem打交道(从内存取指令),要调用内存类内存访问函数,可能涉及不同地址之间的转换与设备映射(在memory/memoey.cpp实现)。在取指令的过程中,涉及到指令的解析,因为X86CPU使用的指令体系属于复杂指令体系(CISC),也就是说每条指令所占的字节数是不一样的,在取指令时不能固定的取2个或4个字节。而是根据指令的具体类型动态决定指令的长度,期间也完成的指令的解析工作。具体函数是fetchInstruction(&iStorage, eipBiased);在cpu/fetchdecode.cpp实现,在解析函数过程中,需要用到X86指令的结构知识,通用的指令有6部分1指令前缀2主操作码3取值方式4:SIB5地址偏移6立即数,也就是说最长指令为这些,很多指令有其中的一部分。而且在设计指令集的时候,追寻逆前缀原则,也就是说给出指令的第一个字节,可以根据它判断出是否有后续,有怎样的后续,一次递推,直到指令全部。在著名的X863卷说明文档Intel ArchitectureSoftware Developer’s Manual里提供相应的查找表,可以根据前个字节,查到相应的后续属性。最复杂的还是取值方式的分析,如:立即数取值,寄存器取值,寄存器间接取值,内存间接取值,基地址取值,偏移地址取值,基地址+偏移地址取值,有32不同的取值方式来取得该运算用到的某一个运算数,不同的取值方式由指令理modR/M为来标记。最后是指令的执行,这涉及到CPU的各种操作。