# 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都会对应去做这样的操作。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://richardweiyang-2.gitbook.io/understanding_qemu/00-vcpu/02-x86_cpu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
