0%

riscv qemu virt平台CPU拓扑分析

riscv的qemu virt平台描述一个完整的机器,这个机器包括CPU、内存、以及各种外设,
在qemu的代码里,这个virt机器用virt-machine类描述,它的实例是RISCVVirtState。

一个RISCVVirtState包含多个RISCVHartArrayState,这个数据结构描述一组CPU core, 一个
RISCVVirtState里会预留一定数量的RISCVHartArrayState,但是机器实际的RISCVHartArrayState
个数是根据qemu启动时配置的numa个数决定的:

1
2
3
/* hw/riscv/virt.c */
virt_machine_init
+-> riscv_socket_count

所以在qemu上RISCVHartArrayState描述的是一个NUMA节点上的CPU core。

RISCVHartArrayState里用RISCVCPU来描述一个具体的CPU core,里面存放CPU的各种参数。
需要注意的是,虽然软件上看CPU似乎是分层的,但是在硬件(qemu)的角度看,CPU上的各种
寄存器只是CPU上的一个变量。RISCVHartArrayState、RISCVCPU都分别对应有自己的类和实例。

用图表示一下,virt平台上各个对象的实例大概就是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
+---------------------------------------------------------------------------------+
| RISCVVirtState |
| |
| +-----------------------------------+ +-----------------------------------+ |
| | RISCVHartArrayState | | RISCVHartArrayState | |
| | | | | |
| |+----------+----------+----------+ | |+----------+----------+----------+ | |
| || RISCVCPU | RISCVCPU | RISCVCPU | | || RISCVCPU | RISCVCPU | RISCVCPU | | |
| |+----------+----------+----------+ | |+----------+----------+----------+ | |
| +-----------------------------------+ +-----------------------------------+ |
| |
+---------------------------------------------------------------------------------+

下面描述如上各个对象的初始化逻辑,整个逻辑从virt平台初始化开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
virt_machine_init
/* 初始化hart_array, 被初始化的hart_array的指针通过&s->soc[i]传入 */
+-> object_initialize_child(OBJECT(machine), soc_name, &s->soc[i], TYPE_RISCV_HART_ARRAY);
/* 触发hart_array的realize函数被调用 */
+-> sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal);
/*
* hart_array的realize函数, 其中会初始化和realize各个hart,因为是在hart_array
* 的上下文,这里就可以针对不同的hart做一些差异化的配置,比如, 下面配置
* 每个hart的hart id。
*/
+-> riscv_harts_realize
/* RISCVCPU的内存是在hart_array的realize函数里申请的 */
+-> s->harts = g_new0(RISCVCPU, s->num_harts);
/* 针对每个hart都调用一个下 */
+-> riscv_hart_realize
/* RISCVCPU初始化, 对应的初始化函数在这里被调用(riscv_cpu_init) */
+-> object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type);
+-> riscv_cpu_init
/* 为每个hart配置复位pc地址 */
+-> qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "resetvec", s->resetvec);
/* 为每个hart配置hart id */
+-> s->harts[idx].env.mhartid = s->hartid_base + idx;
+-> qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
/*
* 触发RISCVCPU的realize函数被调用,其中的细节分析,可以参考下面的链接。
*/
+-> qdev_realize(DEVICE(&s->harts[idx]), NULL, errp); (riscv_cpu_realize)
+-> [...]
+-> qemu_init_vcpu(cs);
+-> cpu_reset(cs);
+-> mcc->parent_realize(dev, errp);

RISCVCPU realize函数细节分析