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函数细节分析