Skip to the content.

TCG

在 notes/zhangfuxin/qemu-llvm-docs/QEMU/QEMU-tcg-02.txt 中存在一些简单的描述 tcg 的大致执行流程,但是这些内容有点老,很多问题也没有分析清楚,下面重新分析一下

问题

/*
 * Translation Cache-related fields of a TB.
 * This struct exists just for convenience; we keep track of TB's in a binary
 * search tree, and the only fields needed to compare TB's in the tree are
 * @ptr and @size.
 * Note: the address of search data can be obtained by adding @size to @ptr.
 */
struct tb_tc {
  void *ptr; /* pointer to the translated code */
  size_t size;
};

就是通过下面的几个变量来实现 tb link 的了

    /* The following data are used to directly call another TB from
     * the code of this one. This can be done either by emitting direct or
     * indirect native jump instructions. These jumps are reset so that the TB
     * just continues its execution. The TB can be linked to another one by
     * setting one of the jump targets (or patching the jump instruction). Only
     * two of such jumps are supported.
     */
    uint16_t jmp_reset_offset[2]; /* offset of original jump target */
#define TB_JMP_RESET_OFFSET_INVALID 0xffff /* indicates no jump generated */
    uintptr_t jmp_target_arg[2];  /* target address or offset */
  /*
   * Each TB has a NULL-terminated list (jmp_list_head) of incoming jumps.
   * Each TB can have two outgoing jumps, and therefore can participate
   * in two lists. The list entries are kept in jmp_list_next[2]. The least
   * significant bit (LSB) of the pointers in these lists is used to encode
   * which of the two list entries is to be used in the pointed TB.
   *
   * List traversals are protected by jmp_lock. The destination TB of each
   * outgoing jump is kept in jmp_dest[] so that the appropriate jmp_lock
   * can be acquired from any origin TB.
   *
   * jmp_dest[] are tagged pointers as well. The LSB is set when the TB is
   * being invalidated, so that no further outgoing jumps from it can be set.
   *
   * jmp_lock also protects the CF_INVALID cflag; a jump must not be chained
   * to a destination TB that has CF_INVALID set.
   */
  uintptr_t jmp_list_head;
  uintptr_t jmp_list_next[2];
  uintptr_t jmp_dest[2];

总体的执行流程

在 cpu_exec 的 while 循环中,tb_find 找到 tb, 然后 cpu_loop_exec_tb 执行 tb

文件结构

target-ARCH/* 定義了如何將 ARCH binary 反匯編成 TCG IR。tcg/ARCH 定義了如何將 TCG IR 翻譯成 ARCH binary。

所以 ./tcg 还存在作用只有 tcg.c 了, tcg/tcg.c 中分别 include 下面几个文件,因为 xqm 抛弃了 tcg, 都是没有作用的了:

#include "tcg-ldst.inc.c"
#include "tcg-target.inc.c"
#include "../tcg-pool.inc.c"

目前将 accel/tcg 和 tcg 下的内容合并到一起了: | Filename | desc | |—————–|———————————————–| | cpu-exec.c | tb 的执行, cpu_exec 的所在地 | | translate-all.c | 主要处理 tb 和 page 的关系,smc, tb_jmp_cache | | cputlb.c | softmmu 管理 | | tcg.c | tb 的内存管理,tb region 之类的 |

tb 查找的过程

首先使用虚拟地址查询(fast),然后使用物理地址查询(slow), 这么设计的原因为: - 在执行 tb 的时候,进行跳转,显然是使用虚拟地址来查询 tb, 如果没有 tb_jmp_cache,那么就首先软件 page walk 计算出来物理地址,使用物理地址来查询

Translated Code Management Captive employs a code cache, similar to QEMU, which maintains the translated code sequences. The key difference is that we index our translations by guest physical address, while QEMU indexes by guest virtual address. The consequence of this is that our translations are retained and re-used for longer, whereas QEMU must invalidate all translations when the guest page tables are changed. In contrast, we only invalidate translations when self-modifying code is detected. We utilize our ability to write-protect virtual pages to efficiently detect when a guest memory write may modify translated code, and hence invalidate translations only when necessary. A further benefit is that translated code is re-used across different virtual mappings to the same physical address, e.g. when using shared libraries.1

这里 Tom Spink 实际上说的并没有什么道理, 对此猜测可能这些东西都是基于早期的 QEMU 吧:

  1. 当 guest page table 发生改变的时候,QEMU 不会 invalidate all translations
  2. 而且 shared libraries 对应的 tb QEMU 也是共享的

tcg region

初始化的工作一直发生在 init thread 中间了:

总之,region 的创建是因为多核,每次分配一个 region,从而用于修改 TCGContext::code_gen_buffer

[ ] cpu_exec_nocache

调用位置

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。

  1. https://www.usenix.org/system/files/atc19-spink.pdf