![skyeye的动态二进制翻译(20210311090303)_第1页](http://file2.renrendoc.com/fileroot_temp3/2021-5/21/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f5/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f51.gif)
![skyeye的动态二进制翻译(20210311090303)_第2页](http://file2.renrendoc.com/fileroot_temp3/2021-5/21/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f5/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f52.gif)
![skyeye的动态二进制翻译(20210311090303)_第3页](http://file2.renrendoc.com/fileroot_temp3/2021-5/21/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f5/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f53.gif)
![skyeye的动态二进制翻译(20210311090303)_第4页](http://file2.renrendoc.com/fileroot_temp3/2021-5/21/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f5/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f54.gif)
![skyeye的动态二进制翻译(20210311090303)_第5页](http://file2.renrendoc.com/fileroot_temp3/2021-5/21/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f5/f1f6d25c-41ca-4d36-8086-e1c2ef53e7f55.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、SKYEYE 指令动态翻译模拟 (DBCT) 实现介绍 v0.0 teawater() 转载请标明来自 http:/ 修改记录: v0.0 2006-06-16 , v0.0 版本编写完成。 2006-05-27 ,文档创建。 目录 1. 写在前面 2. 概述 3. 微指令 3.1. 微指令的结构和初始化 3.2. 微指令中的变量 3.3. 微指令中的函数调用 3.4. 微指令中的异常处理 3.5. 微指令中的跳转 3.6. 微指令分类介绍 3.6.1. 概述 3.6.2. arm2x86.c:op_init 3.6.3. arm2x86_test.c:arm2x86_test_init 3.
2、6.4. arm2x86_shift.c:arm2x86_shift_init 3.6.5. arm2x86_psr.c:arm2x86_psr_init 3.6.6. arm2x86_movl.c:arm2x86_movl_init 3.6.7. arm2x86_mul.c:arm2x86_mul_init 3.6.8. arm2x86_mem.c:arm2x86_mem_init 3.6.9. arm2x86_dp.c:arm2x86_dp_init 3.6.10. arm2x86_coproc.c:arm2x86_coproc_init 3.6.11. arm2x86_other.c:a
3、rm2x86_other_init 4. 翻译块 (TB) 4.1. 概述 4.2. tb.h:struct tb_s 4.3. TB_TBT_SIZE 和 TB_TBP_SIZE 4.4. tb.c:tb_memory_init 4.5. tb.c:tb_insn_len_max_init 5. 初始化函数 arm2x86.c:arm2x86_init 6. 翻译执行过程 6.1. armemu.c:ARMul_Emulate32_dbct 6.2. tb.c:tb_find 6.4. tb.c:tb_translate 6.5. tb.c:translate_word 1. 写在前面 本文
4、针对 skyeye-1.2-RC7-3 进行编写。 关于 skyeye 本身结构的介绍可以参见 skyeye 学习笔记 (http:/ /gshowthreaded.php?Cat=view=collapsed OP_BEGIN 先是一条跳转指令, 跳转到声明在 OP_END 中的符号地址 .f_teawater_op_end , 这句的作用是跳过 OP_BEGIN 和 OP_END 中间的代码, 防止他们被执行, 我为什么没有直 接使用普通的跳转语句 goto 呢?因为如果使用了 goto 语句,编译器就会知道微指令的代码 没被执行, 就会将这部分代码优化掉, 而 使用跳转指令编译器无法判断
5、汇编语句的行为 ,所 以不会优化掉 2 个宏之间的微指令代码。 然后是一条声明符号的伪指令, 这个符号指向的地 址就是微指令开始的地址。 OP_END 先是一条声明符号的伪指令,这个符号的地址就是指向微指令结束的地址, OP_BEGIN 中的跳转指令也是跳到了这个地址。然后跟着是两条赋值指令,将 微指令开始 和结束的地址存到初始化函数开始声明的begin 和 end 变量中, 这样在函数中就取得微指令 的开始和结束地址。 从上面对 2 个宏的的介绍就可以基本清楚微指令的生成过程, 在取得了微指令的开始和结束 地址后,就可以通过计算取得其的长度最后返回。 在 QEMU 的微指令的生成过程跟 DB
6、CT 不同, QEMU 采用的方式是每个微指令都在一个函 数中,编译完成后,通过特定的程序将微指令的开始地址和长度取出。 3.2. 微指令中的变量 在微指令的代码中,都没有使用动态局部变量,也就是栈中的地址,而直接使用了寄存器, 当然在寄存器不够的情况下也使用了全局变量 。这个使用的方法是参考的 QEMU 中微指令 对变量的使用方法。 个人认为这样做因为若干条微指令才能组成一条指令(尤其是在 ARM 这种单条指令实现若 干功能的体系结构更是如此 ),这些微指令之间要相互传递计算等得到的值,如果通过栈传 递也可以,但是实现相对复杂,而且频繁的内存操作速度也会受到影响。 对这些 寄存器的声明在 a
7、rm2x86_self.h 这个单独的头文件中, 因为对寄存器的声明有时候会 影响代码编译,所以只在 DBCT 相关的文件中包含了这个头文件。 ebp寄存器声明为 ARMul_State结构的指针st,其将在微指令的代码开始之前指向state也就 是存储了 SKYEYE 模拟 CPU 所有信息的结构 ,这样微指令就可以方便的访问这个结构。ebx、 esi和edi声明为uint32_t类型的变量T0,T1和T2,这几个变量在微指令中可以灵活使用。 注意因为这几个寄存器保存了栈指针等信息, 所以在运行微指令以前需要进行保存, 具体在 介绍 DBCT 运行的时候会进行介绍。 其他eax等寄存器因为是
8、在 GCC中是局部寄存器,不能作为全局变量声明,所以不能作为 微指令中的变量使用。 3.3. 微指令中的函数调用 在微指令中有时候需要对函数进行调用, 因为微指令使用方法的原因, 这里不能进行普通的 函数调用,而需要特殊处理。 下面就以 arm2x86.c:get_op_begin 中对 tea_begin 函数的调用为例子进行介绍。 这里首先是对esp减Oxc也就是在栈中分配 Oxc的空间,然后将ebp也就是指向ARMul_State 结构的指针push到栈中,这2条汇编指令是将 st作为参数传递给被调用函数tea_begin,前 面在栈中分配Oxc的空间是要保证传递参数的0 x10对齐,O
9、xc加32位的长度就是0 x10。 没有存储使用的ebp、ebx、esi和edi,因为这几个全局寄存器的值是由被调用函数进行保存 的,如果调用函数修改了这几个寄存器的值就进行保存, 在函数返回时恢复, 如果没有就使 用就不进行保存和恢复。 然后是将tea_begin的地址赋值给T2,然后再对其进行调用,这样做的目的是进行直接地址 调用。因为一般的函数调用都是直接地址调用, 所以调用跟当前这个调用指令的地址是相关 的,但是微指令会被拷贝到 TB 上的某地址执行,调用指令的地址发生了变化,所以如果进 行相对地址调用, 肯定要产生错误, 所以这里都使用直接地址调用。 在某些函数中为了适应 CYGWI
10、N 使用函数指针进行调用也是出于同样的目的。 最后是取得返回值,一般一个32位数的返回值都是放在寄存器eax中,如果有需要就将其 存入 T0 等寄存器变量然后使用。 3.4. 微指令中的异常处理 模拟指令一般来说都模拟异常处理, DBCT 也不例外。 DBCT 的做法是当有异常处理的时候,设置 st-trap 或者 state-trap 为异常的类型 (定义在 arm2x86.h,TRAP_XXX 的都是),然后根据情况调用 X86汇编指令ret返回到正常模式,然 后在非 DBCT 运行模式中进行实际的处理。 因为这种处理减少了微指令中实现的难度,所以类似 TRAP_SETS_R15 、 TR
11、AP_SET_CPSR 以及 TRAP_SET_R15 等几个非异常处理 也采用了同一种处理方式。 3.5. 微指令中的跳转 这里的跳转不是指模拟的被模拟指令的跳转, 而是指微指令根据需要跳转指定的长度。 比如 某条被模拟指令有 condition判断,其中就会需要这种跳转,当condition和PSR中的值不 符合的时候, 就需要跳过当前指令被翻译成的微指令代码, 这个时候就需要跳转过指令的长 度。 在 DBCT 中的做法是先写一条类似 _asm_ _volatile_ (jmp 0 xffffffff) ;的指令, 一般来说 后 4 个字节就是跳转长度,在翻译指令的时候将要跳转的长度写入就
12、可以。 在后面介绍 指令翻译过程 的时候,还会对微指令跳转的使用再作详细介绍。 3.6. 微指令分类介绍 3.6.1. 概述 因为规划设计的问题, 微指令的分类有点乱, 所以就以初始化函数为分类基础进行分类介绍。 3.6.2. arm2x86.c op_init 这里初始化的最重要的2个微指令是op_begin和op_begin_test_T0,这2个指令都是在翻译 ARM 指令的时候放在每条指令最开始的部分的。 op_begin 是被翻译的 ARM 指令的 condition 是 AL 或者 NV 也就是不进行条件判断时候使用 的微指令。这里先调用了函数arm2x86.c:tea_begin
13、 ,而这个函数调用了 arm2x86.c: tea_check_out,这个函数类似普通指令执行模式中指令开始执行时候作的操作一 样, 检查是否需要单步返回,检查是否有硬件中断发生进行异常处理,检查当前 TB 是否已 经标记为脏 (如果当前 TB 中执行的微指令写了当前 TB 相关的内存,就会有这样的情况发 生,这时返回到普通模式重新执行,就会自动对这个 TB 进行重新翻译 ),最后一步执行 armio.c:io_do_cycle 调用全部虚拟设备执行。 tea_begin 函数返回以后会判断返回值,如果为 真就返回。 op_begin_test_T0 是被翻译的 ARM 指令需要条件判断时候
14、使用的微指令 。在这条指令运行 以前, 被翻译指令的 condition 已经被存到 T0 中 ,这里首先以 st 和 T0 为参数调用 arm2x86.c:tea_begin_test,这个函数也是调用 tea_check_out检查是否有异常等需要从 DBCT 模式返回普通执行模式, 如果没有则调用 arm2x86_psr.h:gen_op_condition 判断当前被翻译指 令是否可以执行。tea_begin_test返回后,先判断是否有异常需要返回普通执行模式;然后 判断是否这条指令是否因为 condition 而不被执行,如果是则就执行一条 jmp 指令,也就是 前面介绍过的微指令
15、跳转。 其他几个微指令比较简单不作详细介绍。 3.6.3. arm2x86_test.c:arm2x86_test_init 这里初始化了几个简单的测试情况然后进行一些处理的微指令。 3.6.4. arm2x86_shift.c:arm2x86_shift_init 这里初始化的是各种 移位微指令 。 这里移位的长度如果是变量的处理起来比较简单,前面在别的微指令中存到某个寄存器变 量,然后在这条微指令中直接操作就可以。 如果移位的长度是立即数,则处理办法有点类似前面的微指令跳转。先用一条类似“T1 = T1 31; 的语”句,这样其最后一个值是一个 8位的移位长度 ,然后在实际翻译的过程中 替
16、换成实际翻译的立即数就可以了。 3.6.5. arm2x86_psr.c:arm2x86_psr_init 这里初始化的是跟 ARM的状态寄存器PSR(包括CPSR和SPSR)相关的微指令。 3.6.6. arm2x86_movl.c:arm2x86_movl_init 这里 初始化是用来对某模拟寄存器或者某寄存器变量等赋值的微指令。 其中的立即数赋值也比较类似前面的微指令跳转 ,先用类似 “T2 = ULONG_MAX”; 的语句, 这样其最后一个值就是 32 位长度的立即数 ULONG_MAX ,然后在实际翻译的过程中替换 成实际翻译的立即数就可以了。 3.6.7. arm2x86_mul
17、.c:arm2x86_mul_init 这里 初始化是用来对乘法指令进行模拟的微指令 。 3.6.8. arm2x86_mem.c:arm2x86_mem_init 这里 初始化是用来对内存操作进行模拟的微指令 。 这里对内存的操作采用的办法是调用 SKYEYE 原有的内存操作函数,直接取得返回值,然 后进行各种操作。这里这么做而不是直接访问相应的内存地址,因为有 MMU 的时候,需 要先通过 MMU 中的 TLB 和页表等转换地址, 而且还有地址是 IO 地址, 所以直接调用内存 操作函数是比较简单的实现方法。 3.6.9. arm2x86_dp.c:arm2x86_dp_init 这里初始
18、化的是对 ARM 中 DP 指令 进行模拟的微指令。 3.6.10. arm2x86_coproc.c:arm2x86_coproc_init 这里初始化的是对 ARM 中 协处理器指令 进行模拟的微指令。 3.6.11. arm2x86_other.c:arm2x86_other_init 这里对所有 其他微指令 进行初始化。 4. 翻译块(TB) 4.1.概述 在 DBCT 中,将 tb.h:TB_LEN 长度的被模拟指令翻译成一系列微指令 (这一系列 微指令的长 度最大值为 tb.h:TB_INSN_LEN_MAX ,由 tb.c:tb_insn_len_max_init 取得 ) ,这
19、一系列微指令 (存储这些微指令的内存称为 TBP)以及地址信息等其他信息封装在一起称为一个TB。在 DBCT 初始化的时候, 会根据配置文件以及实际情况对 TB 进行初始化, 介绍 tb_memory_init 的时候会详细进行介绍。 4.2. tb.h:struct tb_s 这个结构是 TB 的核心结构,每个 TB 块都将对应一个 tb_s 结构。 下面对其的每个成员变量进行介绍: struct list_headlist; 当使用第二种方法使用 TB 的时候,这个 list 将所有使用过的 TB 全部用 tb.c:tbp_dynamic_list 以及这个 list 结构组成的链表连接起
20、来,在每次使用某个 TB 的时候,都将其先从链表中删 除,然后连接到链表的最后。当对某地址进行执行 ,而所有 TB 都不是这个地址相关的,并 且没有未使用过的 TB ,需要从现有 TB 中选择一个 TB 使用的时候,就会 使用链表第一个 TB 。这样做的好处是,最不常用的已翻译过的 TB 肯定是在链表第一个,选择其影响会最 小,提高了效率。在后面介绍翻译执行的时候会进行更具体的介绍。 int ted; 这个变量为 0 表明这个 TB 中数据是没有翻译过的,为 1 表明其中数据是翻译过的。在需要 标记某个TB为脏的时候,就可以通过设置ted为0来实现。 uint8_t*insn_addrTB_L
21、EN / sizeof(uint8_t *); 在翻译过程中, 将把 每条指令对应的微指令地址 都存储到这个数组中, 这样在执行已经翻译 过的 TB 的时候,可以直接取得对应地址的微指令地址开始执行。 原来的 DBCT 中也采用过不存储微指令地址,在执行的时候再重新翻译取得地址的方法, 最多是将取得后的地址存储起来, 后来考虑即使将所有地址都存起来也不 会使用很多内存, 所以就用了所有翻译过的地址都存起来的方法。 uint8_t*tbp; 这个成员变量指向 当前 TB 存储微指令的内存 ,显然这里指向内存块的大小为 TB_LEN / sizeof (ARMword) * TB_INSN_LEN
22、_MAX 。 ARMwordaddr; 这个成员变量是 当前 TB 对应的被模拟指令的地址 。 ARMwordtran_addr; 在 TB 翻译过程中,并不是一次将整个 TB 范围内的被模拟指令都翻译成微指令,而是每次 翻译到一个 必定发生返回的指令 ,并且实际要取得的微指令地址(注意翻 译是从 TB 开始的 地址开始的 ) 也已经取得, 就不再继续进行翻译, 等下次请求一个地址比翻译到的地址大的 时候,就继续对 TB 进行翻译。 这个成员变量 tran_addr 记录的就是翻译到的指令地址的下一个指令的地址,也就是如果继 续翻译的地址。 uint8_t *tbp_now; 该成员变量指向当
23、前可以写入微指令的地址,在tbt-ted为0也就是这个TB从tbt-addr开 始翻译的时候初始化 为tbt-tbp,每增加一个微指令都顺序增加,并且在向上面 tran_addr 提到的那种继续翻译的时候,可以继续使用。 ARMword last_addr; uint8_t *last_tbp; 这2个成员在指令翻译的时候使用。last_addr存储这个TB上次被使用时候的地址,而last_tbp 就是对应的微指令地址。这样如果下次还使用这个TB的这个地址last_addr,就可以快速 取得微指令地址last_tbp,提高执行速度。 ARMwordret_addr; 介绍 tran_addr
24、的时候,已经提到了只翻译到必定发生返回的指令就不再继续翻译,但是这 里还有一种情况需要考虑到,就是 DBCT 在翻译当前 TB 范围内的 被模拟指令跳转的时候 , 都是将这个跳转指令翻译为微指令跳转指令 ,而不是通常的设置 PC 寄存器然后返回的 方 式,这样的跳转如果是向后跳转,并且超过了翻译结束的地址肯定是不行的。 如何防止提前翻译结束?在翻译开始的时候设置ret_addr为0,一旦有TB内跳转出现,并 且这个地址的值比ret_addr大,就设置ret_addr为这个地址。在翻译完一条指令并确定翻译 也许可以结束的时候,对ret_addr进行检查,只有在 ret_addr小于下一条将翻译的
25、指令地 址的时候,翻译才结束。 4.3. TB_TBT_SIZE 和 TB_TBP_SIZE 在 tb.c 中有 TB_TBT_SIZE 和 TB_TBP_SIZE , TB 的初始化就要根据其的值来进行,他们的 定义为: #define TB_TBT_SIZEskyeye_config.tb_tbt_size #define TB_TBP_SIZEskyeye_config.tb_tbp_size TB_TBT_SIZE是DBCT中所有TB的条目也就是tb_t结构所占空间。如果设置为0则就在 使用的时候分配在被模拟内存结构 armmem.h:mem_state_t-tbt 上,也就是只要运行
26、某块内 存,就分配其的 tb_t 结构。 如果设置为非 0 就使用 tb.c:tbt_table 和 tb.c:tbt_table_size 的内存 进行动态分配。 TB_TBP_SIZE 是 TB 中实际储存微指令的内存所占空间 。如果设置为 0则就在使用的时候 分配在被模拟内存结构 armmem.h:mem_state_t-tbp 上,也就是只要运行某块内存,就分配 其的tbp。如果设置为非 0会同时标记tbp_dynamic为1表明是TBP动态分配,并且 TBP 所用的内存使用 tb.c:tbp_begin、tb.c:tbp_now 和 tbp_now_size 进行动态分配。 skye
27、ye_config.tb_tbt_size 和 skyeye_config.tb_tbp_size 是从配置文件中读出的值, 他们的初始 化也就是 设置默认值在 skyeye_options.c:skyeye_option_init 函数中。在这里我们可以看到 config-tb_tbt_size 也就是 TB_TBT_SIZE 初始化为 0,因为 tb_t 结构占用空间不 大; config-tb_tbp_size 也就是 TB_TBP_SIZE 初始化为 TB_TBP_DEFAULT(1024 * 1024 * 64), 这里没有也初始化因为每条被模拟的 ARM 指令都包含若干条微指令,这
28、样跟 一个 TB 存储 的指令对应的微指令存储空间会比较大 ,甚至有超过 32 位寻址 空间大小的情况, 所以这里 一般不设置为 0。 注意 TB_TBT_SIZE 和 TB_TBP_SIZE 并不是从配置文件中读出后直接使用,而是在 tb_memory_init 进行过初始化后才使用,和其 相关的几个变量也是在 tb_memory_init 中进 行的初始化。 4.4. tb.c:tb_memory_init 这个函数用来对 DBCT 中的 TB 进行初始化。下面介绍执行过程: 第一步,先判断 TB_TBT_SIZE 是否为 0,如果不为 0,就会执行一部分针对 TB_TBT_SIZE 的代
29、码。注意这里我犯了一个比较大的错误,其中的结构应该使用tb_t,而我这里全部错 误的使用了 tb_cache_t,而这个tb_cache_t也是一个不再需要的东西,早应该从代码中去掉, 下面的 介绍全都假定成tb_cache_t已经被换成了 tb_t。先对TB_TBT_SIZE进行基本的处理 和检查,然后取得所有被模拟内存一共需要 tb_t 所 占的空间,其跟 TB_TBT_SIZE 进行比 较。如果TB_TBT_SIZE大于等于这个值,则表明 DBCT不需要动态分配tb_t来节省空间, 就设置 TB_TBT_SIZE 为 0,使用固定分配的形势。如果 TB_TBT_SIZE 小于这个值,则初
30、 始化存储 tb_t 的空间 tbt_table 和 tb_t 的数 量 tbt_table_size 。 这样 TB_TBT_SIZE 就初始化完成,同时还对 tbt_table 和 tbt_table_size 进行了设置。 第二步,如果 TB_TBP_SIZE 为非 0,则对其进行基本的处理和检查。 第三步,再次判断 TB_TBT_SIZE 是否为 0,然后对 TB_TBP_SIZE 进行处理。 如果TB_TBT_SIZE不为0,首先取得这个长度的 tb_t结构组需要的tbp的长度tmp_u64, 跟 TB_TBP_SIZE 进行比较。如果 TB_TBP_SIZE 大于 tmp_u64
31、或者 TB_TBP_SIZE 为 0, 则 TB_TBP_SIZE 设置为这个值,这么作因为在 TB_TBT_SIZE 动态分配后, TB 无法对大 于其管理范围的微指令内存 TBP 进行管理,所以进行这个设置。如果 TB_TBP_SIZE 小于 tmp_u64,则设置 tb.c:tbp_dynamic为1,也就是设置 DBCT中TBP为动态分配。 如果 TB_TBT_SIZE 为 0,将判断 TB_TBP_SIZE 是否为 0。如果为 0 很显然不需要再作任何 初始化工作, tbp_dynamic 使用默认值 0,全部在 DBCT 运行时根据需要分配在 mem_state_t-tbt 和 m
32、em_state_t-tbp 上就可以。如 果不为 0 则先取得全部被模拟内存需要 的TBP的长度tmp_u64,然后跟 TB_TBP_SIZE进行比较。如果 TB_TBP_SIZE大于等于 tmp_u64,则表明TBP已经不需要动态分配,就设置 TB_TBP_SIZE为0。如果TB_TBP_SIZE 小于tmp_u64,则表明需要动态分配,设置tbp_dynamic为1。 这样 TB_TBP_SIZE 就初始化完成,同时也根据需要对 tbp_dynamic 进行了设置。 第四步,这时 TB_TBP_SIZE 的值已经得到了确定,这里就是给 tbp_begin 分配空间,注意 这里用 mmap
33、 分配内存的时候设置了权限为可运行 PROT_EXEC 。然后对 tbp_now_size 和 tbp_now 也进行了初始化。 这样用来进行 TBP 动态分配的 tbp_begin、tbp_now_size 和 tbp_now 进行了初始化。 总结一下, DBCT 中用来维护 TBT 和 TBP 动态分配的几个变量用的有点繁琐了。 4.5. tb.c:tb_insn_len_max_init 这个函数用来对 tb.c:tb_insn_len_max 也就是 TB_INSN_LEN_MAX 进行了初始化。 做法是将所有被翻译指令被翻译成的微指令长度都取得,然后进行比较,将最长的设置为 tb_i
34、nsn_len_max 。 5. 初始化函数 arm2x86.c:arm2x86_init 这个函数是 DBCT 的初始化函数,其在函数 arminit.c:ARMul_Reset 中被调用。 这个函数先会调用前面介绍过的几个微指令初始化函数,然后是函数 tb_insn_len_max_init , 最后是函数 tb_memory_init 。 6. 翻译执行过程 6.1.armemu.c:ARMul_Emulate32_dbct 这是 整个 DBCT 翻译执行的核心函数 ,类似普通指令执行方式的 ARMul_Emulate32 函数, 也是在 arminit.c:ARMul_DoProg 和
35、 arminit.c:ARMul_DoInstr 被调用。下面介绍执行过程: 第一步,给 R15 寄存器也就是 PC 寄存器的值增加一个指令长度 INSN_SIZE ,这是因为 ARM 的多级流水线PC寄存器对应用是非透明的,而在这个函数外面的函数都将R15当作当前 PC值,所以在开始执行前先对R15寄存器进行设置。 第二步,设置 state-trap 为 0。 第三步,调用函数tb.c:tb_find,在这个函数中 根据参数提供的PC寄存器值,进行全部的分 配TB以及指令翻译的工作,最后将跟PC对应的微指令 地址返回。如果返回NULL则表 示执行失败,设置 state-trap为TRAP_I
36、NSN_ABORT 也就是取指异常,跳转到后面对 state-trap 进行处理的部分。 第四步, 对将在微指令中作为变量的寄存器进行保存 ,保存的原因前面介绍过, 因为这几个 寄存器的值都是被调用函数来保存,所以在这里进行保存。 调用取得的指向微指令内存的指针gen_func。 返回后恢复几个寄存器的值。 第五步,在介绍微指令的时候, 介绍过异常等特殊情况, 都是先设置state-trap然后就返回, 而这里就是实际对 异常等进行处理 的地 方。这部分代码比较清晰,就是根据 state-trap 进 行不同的处理,不作详细介绍。 第六步,判断是否还继续执行 ,或者函数返回。如果继续执行就返回
37、到第二步。 第七步,state-Reg15减INSN_SIZE,恢复PC指向当前程序执行的地址,然后返回。 6.2. tb.c:tb_find 在这个函数中 根据参数提供的 PC 寄存器值,进行全部的分配 TB 以及指令翻译的工作 , 最 后将跟 PC 对应的微指令地址返回 。下面介绍执行过程: 第一步,调用 armmmu.c:mmu_v2p_dbct 函数通过 SKYEYE 的 MMU 功能 取得跟执行地址 ADDR对应的被模拟物理地址addr,如果失败则函数出错返回。然后通过TB_ALIGN取得 跟TB_LEN长度对齐的地址 align_addr,这个地址就是 addr对应TB的地址。 第
38、二步, 检查 align_addr 是否和 静态局部变量 save_align_addr 相同, 如果相同表明前面已经 对这个物理地址的 TB 进行过请求,已经取 得了翻译前需要的各种指针,都存在静态局部 变量中, 所以跳过分配 TB 的代码直接执行指令翻译的代码。 注意 save_align_addr 的初始值 为 0 x1 是为了保证不跟任何地址一样。 第三步,这里开始的就是对 TB 进行分配的代码, 首先判断 tbt_table_size 是否为 0 来确定 tb_t 是否是动态分配的。 第四步,如果是动态分配,就会以哈希计算的方法从 tbt_table 中取出跟 align_addr
39、对应地址 的 tb_t。 比较tbt-addr和align_addr,如果tbt-addr跟align_addr不同表明其先前是其他地址的TB, 就会进行一些清除过去记录的工作,设置 tbt-ted 为 0,设置 tbt-addr 为 align_addr。 然后就是取得tbt-tbp也就是TBP。如果tbt-tbp为NULL,则表明这个 TB中的TBP没有 分配或者已经被 其他 TB 使用,这时候需要调用 tb.c:tb_get_tbp 进行 TBP 的分配。如果 tbt-tbp 不为 NULL ,则 TBP 已经分配过, 则按照前面在介绍 tbt-list 那样,先将其从 tbp_dyna
40、mic_list 链表中删除掉。 第五步, 如果不是动态分配, 首先通过函数 tb.c:tb_get_mbp 取得 align_addr 对应模拟内存的 mem_bank_t 结构指针 mbp。 检查结构中的 state-mem.tbtbank_num 是否为空,如果为空表明 tbt 和 tbp 未分配相应的空 间,如果 tbp_dynamic为0表明是静态分配 TBP,则将先给 state-mem.tbpbank_num分配 空间,然后给 state-mem.tbtbank_num 分配空间。 分配好空间后设置 TB 结构。 在取得 TB 结构后检查 tbt-tbp 也就是 TBP 是否为空
41、。如果为空就根据 tbp_dynamic 对其进 行设置,动态分配跟前面一样使用 tb.c:tb_get_tbp 函数,静态从 state-mem.tbpbank_num 中取得。如果不为空也跟前面一样判断 tbp_dynamic 根据情况将 TB 结构从列表中删除。 现在, TB 结构和其中的 TBP 都已经取得。 第六步,用取得的 TB 进行一些设置。 设置 state-tb_now 为刚取得的 TB 结构,其的作用是微指令在运行的时候可以访问当前运行 的TB,比如在标记 TB为脏之后,微指令可以马上判断出来然后退出。 设置为 save_align_addr为 align_addr,目 的
42、在第二步介绍过。 如果 tbp_dynamic 为真表明是动态 TBP 分配,将 TB 结构增加到 tbp_dynamic_list 链表的最 后面,这么作的目的在介绍 tbt-list 已经介绍过。 第七步,现在开始的就是对被模拟指令进行翻译的代码。 先判断 tbt-ted 的值来确定这个 TB 结构是否被翻译过。 第八步,如果这个 TB 结构 已经翻译过 。 先检查 tbt-last_addr 是否跟 addr 相同,如果相同就返回tbt-last_tbp 。这里在前面介绍 tbt-last_addr 和 tbt-last_tbp 的已经介绍过了。 判断需要翻译的物理地址 addr 是否大
43、于等于 tbt-tran_addr ,这个 tbt-tran_addr 在前面也介 绍 过。 如果 addr 小于 tbt-tran_addr 则表明 TB 中现有微指令代码已经可以满足 addr 的需要,直接 从 tbt-insn_addr 取出跟 addr 对应的 TBP 地址作为返回值设置到 ret 就可以。 如果 addr 大于等于 tbt-tran_addr 则表明需要继续翻译, 首先取得跟 tbt-tran_addr 地址对应 的 在被模拟内存块中指针real_begin_addr ,以及和 addr 对应的在被模拟内存块中指针 real_addr。然后就调用tb.c:tb_tra
44、nslate从给定的real_begin_addr开始的内存进行翻译。最后 取得跟 addr 对应的微指令地址设置到 ret。 第九步,如果这个 TB 结构 还没有翻译过 ,就需要重新翻译。 也是首先取得跟tbt-tran_addr地址对应的在被模拟内存块中指针real_begin_addr,以及和 addr对应的在被模拟内存块中指针 real_addr。然后初始化tbt-tran_addr为align_addr,初 始化tbt-tbp_now为tbp,这两个成员变量在前面介绍过,这里就不再介绍。调用 tb.c:tb_translate从给定的real_begin_addr开始的内存进行翻译。
45、最后取得跟addr对应的微 指令地址设置到ret。并且设置tbt-ted为1表明 这个TB已经被翻译过。 现在返回值ret,也就是跟ADDR对应的微指令地址已经取得。 第十步,将 addr 和 ret 都设置到 tbt-last_addr 和 tbt-last_tbp 上,将 ret 返回。 6.3. tb.c: tb_get_tbp 这个函数用来对 TBP 进行动态分配。下面介绍执行过程: 第一步,判断 tbp_now_size 是否为 0,前面介绍过 tbp_now_size 记录了可以分配的 tbp 的长 度。 第二步,如果 tbp_now_size 不是 0,表明还可以直接从tbp_now 中分配 TBP。 第三部, 如果 tbp_now_size 是 0,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024-2030年中国水泥高压釜行业销售模式及未来发展前景分析研究报告
- 2024-2030年中国水分分析仪行业市场发展趋势与前景展望战略分析报告
- 2024-2030年中国氰胺溶液行业市场发展趋势与前景展望战略分析报告
- 2024-2030年中国氧化镓功率元件行业竞争格局与投资趋势预测报告
- 2024-2030年中国氢气压缩系统市场未来趋势及潜力应用需求规模研究报告
- 2024-2030年中国氟泵行业市场现状供需分析及投资评估规划分析研究报告
- 2024-2030年中国气化炉汽轮机行业市场发展趋势与前景展望战略分析报告
- 动画分镜头脚本设计考核试卷
- 机电组件的超声波焊接技术考核试卷
- 毛皮鞣制工厂智能化生产与大数据应用考核试卷
- 2024年公共营养师三级考试试卷及参考答案
- 2024年吉林省白山长白朝鲜族自治县事业单位公开招聘44人历年(高频重点复习提升训练)共500题附带答案详解
- Unit4EverydayEconomicsUsinglanguageIIP55-57教学设计-2023-2024学年高二英语外研版(2019)选择性必修第四册
- 网络安全教育主题班会(完整版)
- DB42-T 1930-2022 地理标志产品 黄梅挑花
- JTS-235-2016水运工程水工建筑物原型观测技术规范
- 2024年四川省精神卫生防治竞赛理论考试题库-上(单选题)
- 文化执法大练兵大比武考试题库大全(含各题型)
- 2024CSCO结直肠癌诊疗指南解读
- 2024届天津市五区县八年级物理第二学期期末统考试题及答案解析
- 大学生毕业论文写作教程(高校毕业生论文写作指课程导)全套教学课件
评论
0/150
提交评论