X86_CPU
正如上一节所说,Qemu中对不同类型的CPU做了具体的模拟。而且根据不同的CPU类型和Machine类型其初始化过程又有些不同。
这里我们就来看看X86_CPU。
继承关系
                                    TYPE_DEVICE
                                    +-------------------------------+
                                    |class_size                     | = sizeof(DeviceClass)
                                    |class_init                     | = device_class_init
                                    |                               |
                                    |instance_size                  | = sizeof(Object)
                                    |instance_init                  | = device_initfn
                                    |instance_finalize              | = device_finalize
                                    |                               |
                                    |realize                        | = x86_cpu_realizefn
                                    +-------------------------------+
                                    TYPE_CPU
                                    +-------------------------------+
                                    |class_size                     | = sizeof(CPUClass)
                                    |class_init                     | = cpu_class_init
                                    |                               |
                                    |instance_size                  | = sizeof(CPUState)
                                    |instance_init                  | = cpu_common_initfn
                                    |instance_finalize              | = cpu_common_finalize
                                    +-------------------------------+
                                    TYPE_X86_CPU
                                    +-------------------------------+
                                    |abstract                       | = true
                                    |class_size                     | = sizeof(X86CPUClass)
                                    |class_init                     | = x86_cpu_common_class_init
                                    |                               |
                                    |instance_size                  | = sizeof(X86CPU)
                                    |instance_init                  | = x86_cpu_initfn
                                    |                               |
                                    |parent_realize                 | = cpu_common_realizefn
                                    +-------------------------------+
   base-x86_64-cpu                                                    qemu64-x86_64-cpu                                                   host-x86_64-cpu
   +-------------------------------+                                  +-------------------------------+                                   +-------------------------------+
   |class_size                     |                                  |class_size                     |                                   |class_size                     |
   |class_init                     | = x86_cpu_base_class_init        |class_init                     | = x86_cpu_cpudef_class_init       |class_init                     | = host_x86_cpu_class_init
   |                               |                                  |                               |                                   |                               |
   |instance_size                  |                                  |instance_size                  |                                   |instance_size                  |
   |instance_init                  |                                  |instance_init                  |                                   |instance_init                  |
   +-------------------------------+                                  +-------------------------------+                                   +-------------------------------+这个继承关系略有点让人烦
- 首先大家都有一个TYPE_X86_CPU的父类 
- 这个父类下又可以生出好多子类 
- 貌似现在默认使用的是qemu64-x86_64-cpu 
类型定义
首先我们要来说说CPU类型定义,不仅使用了常见的方式,还用了一个函数来注册CPU类型。
static void x86_cpu_register_types(void)
{
    int i;
    type_register_static(&x86_cpu_type_info);
    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
        x86_register_cpudef_type(&builtin_x86_defs[i]);
    }
    type_register_static(&max_x86_cpu_type_info);
    type_register_static(&x86_base_cpu_type_info);
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
    type_register_static(&host_x86_cpu_type_info);
#endif
}是不是比之前的有点丑?丑的还没有展开呢。
x86_register_cpudef_type()会对builtin_x86_defs数组一次进行注册,里面标明了具体cpu的型号和对应能支持的功能。那里面简直就是。。。当然看着看着也就习惯了。
指定CPU类型
既然定义了这么多的CPU类型,那就可以在启动qemu的时候指定才对。方法如下:
   -cpu MODEL这里的MODEL就是你可以指定的类型了。具体qemu支持哪些类型,可以通过命令qemu -cpu help来查看。
故事讲到这里就结束本来也是可以的,不过我打算再深入看一下代码中是哪里解析命令行的CPU类型并且找到我们注册的这些类型的。
说起来也不难,就是在main函数中调用了parse_cpu_option这个函数。
 parse_cpu_optioin(), parse option "cpu"
    model_pieces = g_strsplit(cpu_option, ",", 2)
    oc = cpu_class_by_name(CPU_RESOLVING_TYPE, model_pieces)
    cpu_type = object_class_get_name(oc);
        cc->class_by_name(cpu_model) = x86_cpu_class_by_name
    cc->parse_features(cpu_type, ) = x86_cpu_parse_featurestr看明白了,套路就是这么简单。
最终得到的这个类型将被赋值到current_machine->cpu_type等待这后续初始化过程中被使用。
除此之外,还解析了是否有增加或者减少的feature。比如命令行中如下:
-cpu host,+movdir64b,-movdiri这部分将在初始化cpu的时候用到,这里知道就行了。
初始化
从创建Machine开始
CPU和Machine看来还是非常紧密联系在一起的。这点我们从创建cpu的流程中可以看出。
在PCMachine上,cpu初始化的一个简单流程如下:
 pc_init1/pc_q35_init
   x86_cpus_init
       x86_cpu_new()
           object_new(MACHINE(x86ms)->cpu_type)看到了熟悉的cpu_type没有?对了,这个就是之前解析cpu类型时得到的值。由此证明了命令行传入的类型会用来创建cpu。
X86 CPU的初始化细节
CPU的初始化涉及到很多内容,比如支持什么特性,创建vcpu线程,如何接收信号等。在这里我们只是宏观得展开,具体细节有待专门章节讲解。
 object_new(MACHINE(x86ms)->cpu_type)
     cpu_common_initfn
          cpu_exec_initfn()
          x86_cpu_initfn
              x86_cpu_register_feature_bit_props()
              x86_cpu_load_model(xcc->model)
     x86_cpu_realizefn
          x86_cpu_expand_features(), expand cpuid
              plus_features, passed from qemu command line
              minus_features, passed from qemu command line
          x86_cpu_filter_features()
          cpu_exec_realizefn()
              cpu_list_add()
              vmstate_register()
          mce_init()
          qemu_init_vcpu
              qemu_kvm_start_vcpu->qemu_kvm_cpu_thread_fn
          x86_cpu_apic_realize()
              object_property_set_bool(OBJECT(cpu->apic_state), true, "realized",)
              Map APIC MMIO area
          xcc->parent_realize = cpu_common_realizefn作为DEVICE类型的子类,初始化流程自然包含了两个方面:
- instance_init的层次调用 
- realize函数的调用 
仔细看图的朋友估计已经发现了,初始化过程中的第二点,也就是类型中的realize函数发生了微妙的变化。
- Device类型的realize变成了 x86_cpu_realizefn 
- TYPE_X86_CPU的realize变成了 cpu_common_realizefn 
这个偷梁换柱的工作是 x86_cpu_common_class_init 干的。
所以当一个cpu要实例化的时候,调用的realize函数会走到x86_cpu_realizefn,而不是通常的cpu_common_realizefn。
在整个realize过程中,主要完成了几件事:
- 整理了feature,按照当前的了解就是哪些cpuid是支持的 
- 启动了vcpu线程 
- realize了apic 
因为每个cpu对应一个线程,每个cpu上也有自己的apic,所以每个vcpu都会对应去做这样的操作。
Last updated
Was this helpful?