cpu 模拟设计.ppt
《cpu 模拟设计.ppt》由会员分享,可在线阅读,更多相关《cpu 模拟设计.ppt(81页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Bochs 对CPU的模拟2006.11一,概述Bochs是一个X86的模拟器,它可以模拟几乎所有类型的X86 CPU,包括16位,32位和64位(X86_64)。一个64位的X86可以看作是32位和16位X86的超集。X86_64的工作方式包括以下两类:1,IA-32模式:包括实模式,保护模式和虚拟8086模式三个子模式。2,IA-32e模式:包括长模式和兼容模式。在Bochs中,用BX_CPU_C类来模拟CPU,它支持上面提到的每一种模式。二,BX_CPU_C 类的主要数据成员char name64;代表CPU的名字。unsigned bx_cpuid;CPU的ID号,用于SMP(对称多处
2、理)的机器。bx_gen_reg_t gen_regBX_GENERAL_REGISTERS;bx_gen_reg_t是一个复杂的结构体,它表示一个64位的通用寄存器,其主要成员有:rrx:表示一个完整的64位寄存器。hrx、erx:分别表示64位寄存器的高32位与低32位,这时候64位的寄存器被分割成2个32位寄存器使用。rx:表示erx的低16位,此时寄存器被当作16位寄存器使用。rh、rl:分别表示rx的高8位与低8位,此时rx被分割成2个8位寄存器。gen_reg就是一个代表通用寄存器的数组,BX_GENERAL_REGISTERS是寄存器的个数,如果模拟的是64位处理器,那么BX_G
3、ENERAL_REGISTERS值为16,否则值为8。64位时通用寄存器分别是RAX、RCX、RDX、RBX、RSP、RBP、RSI、RDI、R8R15;32位时没有R8R15。BX_CPU_C 类的主要数据成员(续)Bit64u rip;Bit32u eip;分别是64位模式和32位模式下的指令指示器。bx_segment_reg_t sregs6;bx_segment_reg_t是表示段寄存器的结构,sregs6是表示了6个段寄存器的数组。分别是ES、CS、SS、DS、FS和GS。BX_MEM_C*mem;mem是指向这个CPU所使用的内存的指针。bx_local_apic_c local
4、_apic;bx_local_apic是模拟本地APIC的类,用于SMP系统。unsigned cpu_mode;就是前面提到的CPU的工作模式,主要有5种,分别是实模式(16位模式)、8086虚拟模式(32位模式下的虚拟16位模式)、保护模式(32位模式)、兼容模式(64位模式下的虚拟32位,16位模式)和长模式(64位模式)。分别使用宏BX_MODE_IA32_REAL、BX_MODE_IA32_V8086、BX_MODE_IA32_PROTECTED、BX_MODE_LONG_COMPAT和BX_MODE_LONG_64表示。三,三,BX_CPU_C 类的主要函数成员BX_CPU_C 类
5、的主要函数成员如下:void cpu_loop(Bit32s max_instr_count)cpu_loop是一个非常重要的函数,所有的指令函数都在这里执行。参数max_instr_count表示cpu_loop执行的最大指令数。void prefetch(void)预取指令函数,计算指令的物理地址和其他相关信息,为后面的指令译码作准备。unsigned fetchDecode(Bit8u*iptr,bxInstruction_c*instruction,unsigned remain)unsigned fetchDecode64(Bit8u*iptr,bxInstruction_c*ins
6、truction,unsigned remain)这两个函数用于对指令进行译码,前者按指令长度32位译码,后者按64位译码,参数意义分别是指令的物理地址,空白指令结构和指令长度的最大字节数void boundaryFetch(Bit8u*fetchPtr,unsigned remainingInPage,bxInstruction_c*i)X86的最长指令可以达到15个字节,因此指令可能出现跨页,此时prefetch()+fetchDecode()/fetchDecode64()失败,必须调用boundaryFetch()函数进行跨页取指译码。CPU工作流程:cpu_loop()指令的关键:I
7、P to paddrprefetch()*fetchPtr=BX_CPU_THIS_PTR eipFetchPtr+eipBiased;eipBiased=RIP+BX_CPU_THIS_PTR eipPageBias;laddr CS+IPeipFetchPtr=mem-getHostMemAddr(laddr&0 xfffff000);laddrPageOffset0=laddr&0 xfffff000eipPageOffset0=RIP-(laddr-laddrPageOffset0)eipPageBias=-eipPageOffset0eipFetchPtr:当前页的物理的基址eipB
8、iased=CS&0 x00000fff+IP&0 x00000ffffetchDecode(fetchPtr,)prefetch()函数(指令预取)void BX_CPU_C:prefetch(void)计算laddr /指令所在的线性地址 计算paddr /经过地址翻译得到的指令的物理地址 计算laddrPageOffset0 /指令所在的线性页(虚页)的基地址 计算eipPageOffset0 /RIP-(laddr-laddrPageOffset0),指令所在页基 地址相对于CS的偏移 计算eipPageBias /-eipPageOffset0 计算eipPageWindowSize
9、/页大小,值为4096;计算pAddrA20Page /pAddr&0 xfffff000,指令所在的物理页的基地址 计算eipFetchPtr /通过getHostMemAddr()计算得到的指令所在 页在主机(真实机器)上的基地址所谓指令预取,就是计算指令的物理地址和其他相关信息,为后面的指令译码作准备。prefetch()功能流程fetchDecode()函数(指令译码)指令的结构用一个类指令结构bxInstruction_c 来表示,它的两个主要成员函数下:void(BX_CPU_C:*ResolveModrm)(bxInstruction_c*)BX_CPP_AttrRegparmN
10、(1);/获取指令的类型,类型是由bochs定义的void(BX_CPU_C:*execute)(bxInstruction_c*);/指令对应的执行函数指针基本指令放在一个数组中:static BxOpcodeInfo_t BxOpcodeInfo512*2 第0511项:16bit mode 第5121023项:32bit mode (其中包括了fpu,x86-64,3DNOW,SSE等指令入口)BxOpcodeInfo512 X 2static const BxOpcodeInfo_t BxOpcodeInfo512*2=/512 entries for 16bit mode /*00*
11、/BxAnother|BxLockable,&BX_CPU_C:ADD_EbGb,/*01*/BxAnother|BxLockable,&BX_CPU_C:ADD_EwGw,/*02*/BxAnother,&BX_CPU_C:ADD_GbEb,/*0F FD*/BxAnother|BxPrefixSSE,NULL,BxOpcodeGroupSSE_0ffd,/*0F FE*/BxAnother|BxPrefixSSE,NULL,BxOpcodeGroupSSE_0ffe,/*0F FF*/0,&BX_CPU_C:BxError;fetchDecode()attr=BxOpcodeInfob1+
12、offset.Attrconst BxOpcodeInfo_t*OpcodeInfoPtr=&(BxOpcodeInfob1+offset);根据attr从BxOpcodeInfo 中选择对应的指令instruction-execute=BxOpcodeInfob1+offset.ExecutePtr;boundaryFetch()函数(跨页边界取指)void boundaryFetch(Bit8u*fetchPtr,unsigned remainingInPage,bxInstruction_c*i)因为指令跨页,不能将指令的首地址作为参数传给fetchDecode()/fetchDecod
13、e64(),因此设立临时变量fetchBuffer,用以保存在两页中取出的共15个字节,并将fetchBuffer作为译码的参数。指令的最大长度为15字节,但具体每条指令的长度是不定的,在本次取指过程中为了实现跨页移动了RIP,因此返回之前必须将其复原,函数返回以后,在cpu_loop()里面,会根据实际的指令长度移动RIP。boundaryFetch()主要原理cpu_loop()总流程初始化环境得到指令的线性地址是否有中断待处理prefetch()得到物理地址fetchDecode()取一条指令并译码resolveModRM()得到当前指令模式指令是否是可重复的或重复指令是否执行完BX_C
14、PU_CALL_METHODBX_CPU_CALL_METHODQUANTUM是否到达handleAsyncEvent()处理中断退出ynynyn是否取指译码成功boundaryFetch()跨页边界取指ny 基本内存系统主要文件:Memory.hMemory.ccMisc_mem.cc 主要类:bx_mem_c 类成员分析内存块基指针Bit8u*actual_vector;/实际分配的内存块指针 Bit8u*vector;/经过对齐处理(4K大小 整数倍)内存大小size_t len;/以字节为单位size_t megabytes;/以兆字节为单位 类成员分析Bit8u *rom;/512k
15、 BIOS rom space+128k expansion rom spaceBit8u *bogus;/4k for unexisting memory类初始化方法void init_memory(int memsize)alloc_vector_aligned(memsize+BIOSROMSZ+EXROMSIZE +4096,BX_MEM_VECTOR_ALIGN);BX_MEM_THIS rom=&BX_MEM_THIS vectormemsize BX_MEM_THIS bogus=&BX_MEM_THIS vectormemsize+BIOSROMSZ+EXROMSIZE;内存空
16、间的分配alloc_vector_aligned(size_t bytes,size_t alignment)X86处理器的分页机制(相关寄器)CR0:当CR0PG(表示CR0寄存器的PG位,下同)1时,启用分页机制。CR3:X86处理器通常使用多级页表,CR3中存放着最高级页表的基地址。CR4:当CR4PSE1时,使用4M/2M大小的页面,否则使用4K大小的页面;CR4PAE1时,启用PAE模式(支持36位地址空间的物理内存)。X86处理器的分页机制(页表结构)一,使用4K页面时,分三种情况:1,32位模式(非PAE),使用二级页表。地址结构为:10位页目录表索引(PD)+10位页表索引(P
17、T)+12位页内偏移。2,32位模式(启用PAE),使用三级页表。地址结构为:2位页目录指针表索引(PDP)+9位页目录表索引(PD)+9位页表索引(PT)+12位页内偏移。3,64位模式(X86_64),使用四级页表。地址结构为:16位符号扩展+9位第四级页位图索引(PML4)+9位页目录指针表索引(PDP)+9位页目索引(PD)+9位页表索引(PT)+12位页内偏移。二,使用4M/2M页面时,其实就是将地址结构的最低两级合并,因此,对于非PAE的32位模式,页内偏移为22位,对应4M大小的页面,对于其余两种情况,页内偏移为21位,对应2M大小的页面。注意:PAE通过增加地址总线的方式扩大了
18、支持的物理内存最大值,但仍然使用32位的线性地址,不同的操作系统使用不同的方式去访问36位的物理地址。地址翻译(图解)下图是4K页面,未启用PAE的32位线性地址到物理地址的翻译过程(其他模式原理相同):页表缓冲(TLB)TLB也叫快表,存放着页表的一部分,可以认为是专用于页表的Cache。Bochs中,用以下这个结构体来模拟TLB:struct bx_TLB_entry entryBX_TLB_SIZE BX_CPP_AlignN(16);#if BX_USE_QUICK_TLB_INVALIDATE#define BX_TLB_LPF_VALUE(lpf)(lpf|BX_CPU_THIS_
19、PTR TLB.tlb_invalidate)Bit32u tlb_invalidate;#else#define BX_TLB_LPF_VALUE(lpf)(lpf)#endif TLB;其主要部分是bx_TLB_entry entryBX_TLB_SIZE,它按16字节对齐,BX_TLB_SIZE被定义为1024,因此Bochs的TLB中包括1024个入口。页表缓冲(续)bx_TLB_entry是TLB入口的结构:typedef struct bx_address lpf;/线性页框号(页号)Bit32u ppf;/物理页框号 Bit32u accessBits;bx_hostpagead
20、dr_t hostPageAddr;/该页在真实机器内存中的地址 bx_TLB_entry;其主要部分是线性页框号lpf和物理页框号ppf组成的对。地址翻译Bochs处理地址翻译的主要函数是/cpu/paging.cc中的三个函数:Bit32u translate_linear(bx_address laddr,unsigned pl,unsigned rw,unsigned access_type)Bit32u dtranslate_linear(bx_address laddr,unsigned pl,unsigned rw)Bit32u itranslate_linear(bx_addr
21、ess laddr,unsigned pl)在translate_linear中,参数的意义分别是线性地址值,特权级别,当前操作的访问方式(读、写),操作类型(数据,指令),返回值是翻译后的物理地址。dtranslate_linear和itranslate_linear分别实现数据地址和指令地址的翻译,都是通过调用translate_linear实现的。translate_linear()函数Bit32u用到的局部变量:bx_address pte,pde,pdp,pml4;分别表示页表项,页目录表项,页目录指针表项和PML4表项,这些表项分别包含了本次翻译的页,页表,页目录表,页目录指针表在
22、内存中的基地址。Bit32u pte_addr,pde_addr,pdp_addr,pml4_addr;分别表示本次翻译中页表项,页目录表项,页目录指针表项以及PML4表项自身所在的绝对地址(物理地址)。Bit32u ppf,poffset,paddress;分别表示物理页框地址(物理页的基地址),页内偏移和经过翻译后的物理地址。translate_linear()函数(续)Bit32u translate_linear(bx_address laddr,unsigned pl,unsigned rw,unsigned access_type)#if BX_SUPPORT_PAE#if BX_
23、USE_TLB 查询TLB,如果命中,返回物理地址#endif#if BX_SUPPORT_X86_64 计算pml4_addr,取出pml4 根据pml4计算pdp_addr#endif 计算pdp_addr,取出pdp 根据pdp计算pde_addr,取出pde#if BX_SUPPORT_4MEG_PAGES 根据pde计算ppf#endif 根据pde计算pte_addr,取出pte 根据pte计算ppf#endiftranslate_linear()函数(续)#if BX_USE_TLB 查询TLB,如果命中,返回物理地址#endif 计算pde_addr,取出pde#if BX_S
24、UPPORT_4MEG_PAGES 根据pde计算ppf#endif 根据pde计算pte_addr,取出pte 根据pte计算ppf 用ppf和poffset计算paddress#if BX_USE_TLB 更新TLB#endif 返回paddresstranslate_linear()由laddr得到线性页地址lpf和页内偏移量offsetTLB命中查表得到物理页地址ppf返回ppf|offsetlpf的高10位为页目录表索引readPhysicalPage();得到页目录lpf的22-13位为页表索引readPhysicalPage();得到页地址ppf写TLBY N 内存地址映射gue
25、st physical memory addr=host physical memory addrgetHostMemAddr(BX_CPU_C*cpu,Bit32u a20Addr,unsigned op)if(a20Addr&0 xfffc0000)!=0 x000c0000)return(Bit8u*)&vectora20Addr);/common memory space if(a20Addr&0 xfffe0000)=0 x000e0000)return(Bit8u*)&roma20Addr&BIOS_MASK);/rom memory space else /Error,reque
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- cpu 模拟设计 模拟 设计
限制150内