qemu之linux-user分析 1

本文档详细分析了QEMU Linux-User模式的主代码流程,重点关注`cpu_loop`中的死循环以及`cpu_exec`、`cpu_exec_start`和`cpu_exec_end`等关键函数。作者探讨了代码块的处理,包括解码、执行和异常处理,尤其是系统调用(syscall)的触发和管理。通过对QEMU源码的深入剖析,揭示了代码如何在用户空间模拟CPU执行,并处理各种异常情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最后更新2021/12/26

这几天研究qemu linux-user有关的问题,此地立个桩,把我认为值得记录的研究结果记录在此。qemu整体的编译不细说了,只针对我需要的ppc64相关关键记录,很大众、特别是没遇到问题的过程就不记录了,也许以后整理全本说明的时候补充一下。另外由于我的最终目标是搞aix-user,与aix-user相关的内容也许会在这里有关联,但全部的内容应在另一个专题中,此处都是linux-user的东西。需要继续分析的标记为黑体,随时更新。

前置

通过configure定义目标,我用的是:

./configure --target-list="ppc64-softmmu ppc64-linux-user" --disable-curses --disable-kvm --disable-sdl

除了disable-curses是为了填wsl上libtinfow.so.6 missing的老坑,别的随意。

然后make,如果一切正常,会搞出两个可执行文件,一个用于虚拟ppc64 machine,另一个可作为ppc64 linux elf程序的加载器:

ppc64-softmmu/qemu-system-ppc64
ppc64-linux-user/qemu-ppc64 

本系列只研究linux-user。

顺序结构

主代码在linux-user/main.c

从main()开始,都是各种初始化,涉及到的时候会更新本文,不需要仔细研究,则先承认,需要的时候再分析。我喜欢直达关键点,其它的东西遇到再说。虽然这种方法不太适合一层层抽丝剥茧,特别是没有任何概念的时候,一下子跳得太远,思维会乱,也不适合学习。但对我现在的研究来说,比较节省时间,而且如果走太多岔路,最后都不知道转到哪里去了,把主线荒废了。以走迷宫比喻,一种方法是从入口遍历每个岔路,这种适合对迷宫有透彻全面的了解;而我喜欢先到出口,反向走逆推,先通过再说,走迷宫不是我的目的,通过迷宫才是。所以,我们就直接翻到main.c的最后几行:
cpu_loop(env);

cpu_loop里面是个死循环

到了cpu_loop,则所有初始化等准备工作都已经完成,包括待加载执行文件格式审核、加载到内存等等,马上需要做的只是解码执行了。

在很多文件中都有cpu_loop调用,真正被使用的是对应目标cpu架构下的cpu_loop,我这里用的是linux-user/ppc/cpu_loop.c

cpu_loop()看起来也很简单,进来就是个for死循环,在里面完成这么几个操作:

    for (;;) {
   
        cpu_exec_start(cs);
        trapnr = cpu_exec(cs);
        cpu_exec_end(cs);
        process_queued_cpu_work(cs);
        ...
        switch (trapnr) {
   
            case POWERPC_EXCP_NONE:
            ...
        }
        process_pending_signals(env);
    }

这里有个背景知识,qemu执行目标代码是以jump block为单位整体处理之后再执行,每个jump block(程序中名称直译是翻译块,我觉得不形象贴切,所以自己起了个名字,也许以后会改更好的名字)是一组将要被连续执行的代码,直到需要跳转到其它地址或者发生意外中断等等情况发生,才结束一块,也许块太大也是一个分割条件,待确认。

那么,这个程序结构就很清晰了,代码从cs指定位置开始做准备,(解码、生成tcg代码等等,在cpu_exec里完成)解码顺序执行,直到本块执行完或者发生意外(此意外包含所有意外还是只包含guest代码意外待确认,目前认为包含所有意外),返回后,进行块后处理,此块将被保留,下次再跑到这个地址,就无需解码,可以直接执行,就更快了。这个过程类似java的JIT解释执行过程。

这里有个潜在的情况,就是代码块的连续性,会存在代码块解码时是连续的,运行时会提前中断跳出,或者虽然是跳转,本应两个代码块,但前后两个代码块其实可以合并到一起。这些问题qemu都有考虑,后续深入分析的时候能解析具体相应处理过程逻辑。

代码块预处理(cpu_exec_start),主操作(cpu_exec),后处理(cpu_exec_end),再加上一个排队中的cpu任务处理(process_queued_cpu_work)都完成后就是意外处理,一个switch,case一堆的意外类型。这里也有我要关注的syscall问题。

        case POWERPC_EXCP_SYSCALL_USER:
            /* system call in user-mode emulation */
            /* WARNING:
             * PPC ABI uses overflow flag in cr0 to signal an error
             * in syscalls.
             */
            env->crf[0] &= ~0x1;
            env->nip += 4;
            ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
                             env->gpr[5], env
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ensighine

如需特定专题,踢我

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值