【QEMU源码】cpu_exec_loop实现

cpu_exec_loop函数流程概述

cpu_exec_loop是TCG执行的主要循环函数,负责处理异常、中断和TB(Translation Block)的查找执行循环

1. 异常处理外层循环

函数首先进入异常处理循环,通过cpu_handle_exception检查是否有待处理的异常

cpu-exec.c:921 

    /* if an exception is pending, we execute it here */
    while (!cpu_handle_exception(cpu, &ret))

如果有异常需要处理,函数会退出并返回相应的异常码

cpu-exec.c:686-749 

    static inline bool cpu_handle_exception(CPUState *cpu, int *ret) {}

2. 中断处理内层循环

在异常处理循环内部,函数进入中断处理循环,通过cpu_handle_interrupt检查中断请求

cpu-exec.c:925 

while (!cpu_handle_interrupt(cpu, &last_tb)){

}

中断处理函数会检查各种中断标志,包括调试中断、复位中断等

cpu-exec.c:764-865 


static inline bool cpu_handle_interrupt(CPUState *cpu,
    TranslationBlock **last_tb) {
}

3. TB预处理

在中断处理循环内部,函数执行核心的TB查找和执行逻辑:

获取CPU状态:通过get_tb_cpu_state获取当前CPU状态,包括PC、CS基址、标志位等

cpu-exec.c:927-928 

    TranslationBlock *tb;
    TCGTBCPUState s = cpu->cc->tcg_ops->get_tb_cpu_state(cpu);
    s.cflags = cpu->cflags_next_tb;

处理编译标志:检查是否有特定的编译标志需要应用,如单步调试、指令计数等

cpu-exec.c:937-941 


/*
* When requested, use an exact setting for cflags for the next
* execution.  This is used for icount, precise smc, and stop-
* after-access watchpoints.  Since this request should never
* have CF_INVALID set, -1 is a convenient invalid value that
* does not require tcg headers for cpu_common_reset.
*/
if (s.cflags == -1) {
    s.cflags = curr_cflags(cpu);
} else {
    cpu->cflags_next_tb = -1;
}

断点检查:调用check_for_breakpoints检查是否命中断点

cpu-exec.c:943-945 


if (check_for_breakpoints(cpu, s.pc, &s.cflags)) {
    break;
}

4. TB查找或生成

TB查找:使用tb_lookup函数在缓存中查找现有的TB

cpu-exec.c:947 


tb = tb_lookup(cpu, s);

TB生成:如果TB不存在,调用tb_gen_code生成新的TB

cpu-exec.c:948-954 

if (tb == NULL) {
    CPUJumpCache *jc;
    uint32_t h;

    mmap_lock();
    tb = tb_gen_code(cpu, s);
    mmap_unlock();
    ...
}

缓存更新:将新生成的TB添加到跳转缓存中

cpu-exec.c:960-964 

if (tb == NULL) {
    ...
    /*
        * We add the TB in the virtual pc hash table
        * for the fast lookup
        */
    h = tb_jmp_cache_hash_func(s.pc);
    jc = cpu->tb_jmp_cache;
    jc->array[h].pc = s.pc;
    qatomic_set(&jc->array[h].tb, tb);
}

5. TB链接优化

跨页检查:在系统模式下,检查TB是否跨越页面边界,如果是则不能建立直接链接

cpu-exec.c:973-976 


if (tb_page_addr1(tb) != -1) {
    last_tb = NULL;
}

TB链接:如果存在上一个TB且满足条件,调用tb_add_jump建立直接跳转链接

cpu-exec.c:978-980 

/* See if we can patch the calling TB. */
if (last_tb) {
    tb_add_jump(last_tb, tb_exit, tb);
}

6. TB执行

执行TB

调用cpu_loop_exec_tb执行当前TB cpu-exec.c:982 。

该函数内部会调用cpu_tb_exec执行实际的机器码 cpu-exec.c:871-872 。

时钟同步:执行完TB后,调用align_clocks进行时钟同步

cpu-exec.c:986 


            /* Try to align the host and virtual clocks
               if the guest is in advance */
            align_clocks(sc, cpu);

7. 指令计数处理

cpu_loop_exec_tb函数中,还会处理指令计数相关的逻辑:

指令计数检查:如果启用了指令计数,会检查是否达到指令限制 cpu-exec.c:891 。

计数器更新:更新指令计数器并重新填充 cpu-exec.c:894-899 。

动态标志调整:根据剩余指令数动态调整编译标志 cpu-exec.c:905-909 。

全部评论

相关推荐

秋招结束已经一段时间了 一直在忙着毕业的事情 浅浅总结一下自己的秋招经历吧~本人BG双非硕 后端选手 有一段小厂+腾讯暑期实习腾讯暑期转正loser秋招结束已经结束了有一段时间了总结一下秋招历程最大的感受就是秋招比起暑期更加卡学历秋招总共投了60多家吧一直面 一直挂也投了两家银行科技岗 都走到终面体检了都拒了(总体感觉本地的银行还是挺容易过的)可能本人更想去私企 并且银行也挺卷听说一直到11月就只有一家小厂的offer并签约当保底然后也突然被WXG捞了 本来都不对腾讯抱有希望了可能经过一整个秋招的面试积累吧 以及本人有ACM经历 WXG整体面试以做题偏多(一二面做了5道题 4道hard) 比较合自己胃口 差不多半个月就把五轮面试过了进入录用评估 但也一直没有结果到后面也陆陆续续有几家中厂也终面过泡池子一直到12月初华子给开了base杭州 14a因为华子公积金的原因 和小厂薪资上差距不大 所以也一直犹豫是否毁约签华子 但是内心也还对WXG抱有一丝幻想(虽然一直没有保温也没有任何消息)然后一直到12月中下旬 华子要求去现场签约了 但是WXG还是没有消息 然后就连续发邮件和打电话催了好多次 还是回复耐心等待直到华子签约那天 经过内心挣扎已经决定毁约签华子了 可能还是想平台更大一点吧 然后最戏剧性的一幕来了 就在我发毁约邮件没有5秒 WXG打电话开奖了 并且开奖也十分有诚意 最终还是没有签约成功华子 研究生期间也打了很多次华子的比赛还是对华子有感情的555整个秋招都是伴随着焦虑的 我认为自己也是秋招大部分人的画像 屡屡碰壁后不断怀疑自己 但是可能自己也比较幸运吧 但是也感谢自己在一次次陷入迷茫都没有放弃自己 还是一直努力背八股 刷题也祝各位牛友们共勉 就算暂时没有好的offer 不放弃一定会有好的结果的!!
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务