当前位置: 首页 > news >正文

QEMU RISCV TCG 详解六 -- RISCV CPU 的使能(How a RISCV CPU Realized)

        当 RISCV CPU 被创建(Created),被初始化(Initialized)后,要使得其开始运行,需要让其使能(Realized)。Realize 过程如下代码片段:

static void cpu_create(MachineState *machine) {MyMachineState *s = RISCV_VIRT_MACHINE(machine);// create clusterobject_initialize_child(OBJECT(machine), "cluster", &s->cluster,TYPE_CPU_CLUSTER);qdev_prop_set_uint32(DEVICE(&s->cluster), "cluster-id", 0);// create hart array and initialize cpusobject_initialize_child(OBJECT(&s->cluster), "cpus", &s->cpus,TYPE_RISCV_HART_ARRAY);object_property_set_str(OBJECT(&s->cpus), "cpu-type", TYPE_RISCV_CPU_BASE,&error_abort);object_property_set_int(OBJECT(&s->cpus), "hartid-base", 0, &error_abort);object_property_set_int(OBJECT(&s->cpus), "num-harts",   1, &error_abort);object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x0,&error_abort);// realize cpus sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal);// realize clusterqdev_realize(DEVICE(&s->cluster), NULL, &error_abort);
}

        其中,object_initialize_child() 创建及初始化对应的CPUs,后续的 object_property_set_*() 设置对应的属性,然后调用 sysbus_realize() 来使得 CPUs realized.

bool sysbus_realize(SysBusDevice *dev, Error **errp){return qdev_realize(DEVICE(dev), sysbus_get_default(), errp);
}bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp){
...return object_property_set_bool(OBJECT(dev), "realized", true, errp);
}

        当 TYPE_RISCV_HART_ARRAY 的 realized property 被设置为 true 的时候,会调用 riscv_harts_realize() -> riscv_hart_realize(),然后再对单个的CPU 使用 qdev_realize(),从而使得 riscv_cpu_realize() 被调用。

        这里使用了 realized property 的机制,当该属性被设置值时,会调用其 set() 函数,即 ObjectPropertyAccessor * ObjectProperty::set。然而 realize property 的定义如下:

static void device_class_init(ObjectClass *class, const void *data){
...object_class_property_add_bool(class, "realized",device_get_realized, device_set_realized);
...}static void device_set_realized(Object *obj, bool value, Error **errp) {DeviceState *dev = DEVICE(obj);DeviceClass *dc = DEVICE_GET_CLASS(dev);...if (value && !dev->realized) {...if (dc->realize) {dc->realize(dev, &local_err);......} else if (!value && dev->realized) {...}
...}

        因此,再查看对应的 DeviceClass::realize() 是否被设置,如下:

// Harts' Device Class
static void riscv_harts_class_init(ObjectClass *klass, const void *data){DeviceClass *dc = DEVICE_CLASS(klass);device_class_set_props(dc, riscv_harts_props);dc->realize = riscv_harts_realize;
}// RISCV CPU's Device Class
static void riscv_cpu_common_class_init(ObjectClass *c, const void *data){RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);CPUClass *cc = CPU_CLASS(c);DeviceClass *dc = DEVICE_CLASS(c);
...device_class_set_parent_realize(dc, riscv_cpu_realize,&mcc->parent_realize);
...
}void device_class_set_parent_realize(DeviceClass *dc,DeviceRealize dev_realize,DeviceRealize *parent_realize){*parent_realize = dc->realize;dc->realize = dev_realize;
}

        这里 RISCV CPU 保留了其父类的 realize() 函数,即 CPUClass::realize(),并在RISCVCPUClass::realize() 调用的最后阶段调用 CPUClass::realize()。代码如下:

//Set CPUClass::realize()
static void cpu_common_class_init(ObjectClass *klass, const void *data){DeviceClass *dc = DEVICE_CLASS(klass);
...dc->realize = cpu_common_realizefn;
...}static void riscv_cpu_realize(DeviceState *dev, Error **errp){CPUState *cs = CPU(dev);
...qemu_init_vcpu(cs);cpu_reset(cs);mcc->parent_realize(dev, errp);
}

        当 RISCV CPU 进行 realize 的时候,调用了 qemu_init_vcpu(),用于创建CPU的执行过程,如下:

void qemu_init_vcpu(CPUState *cpu){MachineState *ms = MACHINE(qdev_get_machine());cpu->nr_threads =  ms->smp.threads;cpu->stopped = true;cpu->random_seed = qemu_guest_random_seed_thread_part1();if (!cpu->as) {/* If the target cpu hasn't set up any address spaces itself,* give it the default one.*/cpu->num_ases = 1;cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);}/* accelerators all implement the AccelOpsClass */g_assert(cpus_accel != NULL && cpus_accel->create_vcpu_thread != NULL);cpus_accel->create_vcpu_thread(cpu);while (!cpu->created) {qemu_cond_wait(&qemu_cpu_cond, &bql);}
}

        其中,cpus_accel->create_vcpu_thread(),对应的就是 TCG 的 mttcg_start_vcpu_thread(),该接口函数的设置如下:


static void tcg_accel_ops_init(AccelOpsClass *ops){if (qemu_tcg_mttcg_enabled()) {ops->create_vcpu_thread = mttcg_start_vcpu_thread;ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;ops->handle_interrupt = tcg_handle_interrupt;} else {...}ops->cpu_reset_hold = tcg_cpu_reset_hold;ops->supports_guest_debug = tcg_supports_guest_debug;ops->insert_breakpoint = tcg_insert_breakpoint;ops->remove_breakpoint = tcg_remove_breakpoint;ops->remove_all_breakpoints = tcg_remove_all_breakpoints;
}static void tcg_accel_ops_class_init(ObjectClass *oc, const void *data){AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);ops->ops_init = tcg_accel_ops_init;
}
static const TypeInfo tcg_accel_ops_type = {.name = ACCEL_OPS_NAME("tcg"),.parent = TYPE_ACCEL_OPS,.class_init = tcg_accel_ops_class_init,.abstract = true,
};
module_obj(ACCEL_OPS_NAME("tcg"));
static void tcg_accel_ops_register_types(void){type_register_static(&tcg_accel_ops_type);
}
type_init(tcg_accel_ops_register_types);

        其中,TCG 就是其中一种QEMU加速器(Accelerator),另外还有 KVM,XEN,HVF等。这个就不展开来说了。

        另外,mttcg_start_vcpu_thread() 就接上了本系列的第一篇文章《QEMU RISCV TCG 详解一 -- 主执行循环(Main Execution Loop)》 了。

        回到 qemu_init_vcpu() 函数,其中 有 cpu->stopped = true,那么,在TCG的最外层执行循环中,即 mttcg_cpu_thread_fn() 函数中循环,一直等待 CPU stopped 改为 false,从而进入执行状态,代码如下:

/** In the multi-threaded case each vCPU has its own thread. The TLS* variable current_cpu can be used deep in the code to find the* current CPUState for a given thread.*/
static void *mttcg_cpu_thread_fn(void *arg){ ...do {if (cpu_can_run(cpu)) {int r;...r = tcg_cpu_exec(cpu);...}
...} while (!cpu->unplug || cpu_can_run(cpu));
...}
bool cpu_can_run(CPUState *cpu){if (cpu->stop) {return false;}if (cpu_is_stopped(cpu)) {return false;}return true;
}
bool cpu_is_stopped(CPUState *cpu){return cpu->stopped || !runstate_is_running();
}

        当整个 SoC(Machine)都创建完成、初始化完成、使能完成,后,qemu主线程会调用 vm_start() -> resume_all_vcpus() -> cpu_resume(),从而改变 cpu->stop 和 cpu->stopped 为 false,让 cpu 执行线程开始运作。

        回到 riscv_cpu_realize() 函数,除了 创建及初始化 CPU 执行线程外,还 重置(reset)了 CPU,即:

void cpu_reset(CPUState *cpu){device_cold_reset(DEVICE(cpu));
...}

        从而进一步地让 CPU 处于重置状态,等待最初执行的开始。cpu_reset 会最终调用 riscv_cpu_reset_hold() -> cpu_common_reset_hold() 等一系列的 cpu 重置函数 *reset*()。这里可以看到:

static void cpu_common_reset_hold(Object *obj, ResetType type){CPUState *cpu = CPU(obj);
...cpu->cflags_next_tb = -1;
...}

        cflags_next_tb 就是在 TCGTBCPUState::cflags 的初始值。

        总结一下:RISCV CPU 的初始过程有:

1. RISCV CPU 类型的注册,基于QEMU类型注册机制, type_init();

2. RISCV CPU 的创建,基于 QOM 机制;

3. RISCV CPU 的初始化,基于QOM机制;

4. RISCV CPU 的使得(realize),基于 realize 属性(property)机制,属于 QOM 的一部分;

5. RISCV CPU 的执行(TCG 执行循环)。

http://www.dtcms.com/a/297864.html

相关文章:

  • 算法:数组part02: 209. 长度最小的子数组 +
  • 视频孪生技术赋能仓储智慧化转型
  • Leetcode力扣解题记录--第21题(合并链表)
  • 已解决:Please check the setting of primary
  • 自定义控件
  • 逆向工程信息抽象层次详解
  • 指令改图,换背景/改文字/调光影等
  • Spring Boot2 静态资源、Rest映射、请求映射源码分析
  • SAP在未启用负库存的情况下,库存却出现了负数-补充S4 1709 BUG
  • Text Edit + ComboBox 属性(2)
  • SpringBoot(黑马)
  • Ansible自动化运维工具详解
  • n8n插件增加repeat_penalty参数适配Qwen3
  • HCIA再复习
  • 3款好用的服装外贸系统对比分析
  • 蜘蛛强引的原理与百度SEO的关系
  • 无人机视觉模块技术解析
  • 【算法-图论】图的存储
  • Gitee Test:国产软件测试平台如何筑牢关键领域数字安全屏障
  • 【SpringAI实战】ChatPDF实现RAG知识库
  • 二重循环之在ATM上取款
  • 【vue3+vue-pdf-embed】实现PDF+图片预览
  • InfluxDB Line Protocol 协议深度剖析(二)
  • Ubuntu 22.04 使用 Issac Gym 进行人形强化学习训练
  • ip link show 查看/配置网络接口
  • keepalived篇
  • Spring Cloud微服务项目完整搭建指南
  • ODFM(正交频分复用)系统中加入汉明码(Hamming Code)的主要目的是增强抗误码能力,通过**前向纠错(FEC)**机制提高传输可靠性
  • 详解FreeRTOS开发过程(八)-- 时间标志
  • 相机ROI 参数