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

QEMU RISCV TCG 详解二 -- RISCV CPU Representation

        在 QEMU 里,如何表征 RISCV CPU 呢?该代码就位于 qemu/target/riscv/cpu-qom.h 中。如下:

// qemu/target/riscv/cpu-qom.h:60
OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU)

        经过宏扩展(Macro Preprocess)后,有

# 60 "../target/riscv/cpu-qom.h"
typedef struct ArchCPU RISCVCPU;
typedef struct ArchCPU ArchCPU;
typedef struct RISCVCPUClass RISCVCPUClass;
typedef ArchCPU *ArchCPU_autoptr;
typedef GList *ArchCPU_listautoptr;
typedef GSList *ArchCPU_slistautoptr;
typedef GQueue *ArchCPU_queueautoptr;

        其中类型 ArchCPU 就是 QEMU中,对某一 ISA 的 CPU 的表征(Representation)。那么,对于 RISCV ISA来说,自然就是 类型 RISCVCPU 了。

        另外,基于 QEMU 的 QOM 框架,即基于 C 语言来实现的类似与C++中的面向对象机制(Object Oriented Mechanism),有,类型 RISCVCPU 为 InstanceType,其对应的 ClassType 为 RISCVCPUClass。就像之前,C++还没有自己专用的编译器时,需要先将 C++ 编译成 C 再 编译成二进制码那样。也类似于 Objective-C 中的运行时(runtime)那样。

        即,如果由 C++ 实现为:

// pesudo code of RISCV CPU in C++ as in C with QEMU QOM
class RISCVCPUClass {// data membersRISCVCPU cpu;// with some methodsauto methods();// class data membersstatic class_members;// with some class methodsauto class_methods();
}

        即,类型 RISCVCPU 封装了 RISCVCPUClass 的成员及成员函数,RISCVCPUClass 封装了 类成员及函数。其中,实例类型(InstanceType)中有一成员 ObjectClass *class 指向其 RISCVCPUClass。注意,成员函数(member methods)是存放在 Class 中的,而非实例中的。实例只包含对应的数据成员(data member)。

        对于 RISCVCPU 的 QOM 构建过程,会在后续博文进行详细讲解。这就可以简单地,类似上面 C++ 实现的方式进行理解。

        那么,对于 RISCV 的 ArchCPU 的定义如下:

/** RISCVCPU:* @env: #CPURISCVState** A RISCV CPU.*/
struct ArchCPU {CPUState parent_obj;CPURISCVState env;GDBFeature dyn_csr_feature;GDBFeature dyn_vreg_feature;/* Configuration Settings */RISCVCPUConfig cfg;RISCVSATPModes satp_modes;QEMUTimer *pmu_timer;/* A bitmask of Available programmable counters */uint32_t pmu_avail_ctrs;/* Mapping of events to counters */GHashTable *pmu_event_ctr_map;const GPtrArray *decoders;
};

        其中包含了 CPUState parent_obj 以及 CPURISCVState env。

        1. CPUState parent_obj 包含所有不同架构的CPU的共同信息。类似如下C++实现:

// pesudo code of RISCV CPU in C++ as in C with QEMU QOM
class RISCVCPU: public CPUState {// data membersauto data_members;
}class RISCVCPUClass: public CPUClass {// data membersRISCVCPU cpu;// with some methodsauto methods();// class data membersstatic class_members;// with some class methodsauto class_methods();
}

        2.  CPURISCVState env 包含特定架构特有的状态信息,如各个通用寄存器、状态寄存器等。其中 RISCV ISA 的如下:

typedef struct CPUArchState CPURISCVState;
struct CPUArchState {target_ulong gpr[32];target_ulong gprh[32]; /* 64 top bits of the 128-bit registers *//* vector coprocessor state. */...target_ulong pc;.../* Floating-Point state */.../* RISCVMXL, but uint32_t for vmstate migration */.../* 128-bit helpers upper part return value */....../* RNMI */...
};

        其中,在 CPUState 结构体中的最后一个成员,CPUNegativeOffsetState neg,是以ArchCPU::env 为基准来访问,即:

/*** struct CPUState - common state of one CPU core or thread.* @neg: The architectural register state ("cpu_env") immediately follows* CPUState in ArchCPU and is passed to TCG code. The @neg structure holds* some common TCG CPU variables which are accessed with a negative offset* from cpu_env.*/
struct CPUState {
.../** MUST BE LAST in order to minimize the displacement to CPUArchState.*/char neg_align[-sizeof(CPUNegativeOffsetState) % 16] QEMU_ALIGNED(16);CPUNegativeOffsetState neg;
};
/** RISCVCPU:* @env: #CPURISCVState** A RISCV CPU.*/
struct ArchCPU {CPUState parent_obj;CPURISCVState env;
...
}

        由此,可见 CPUState parent_obj 在地址中是位于 CPURISCVState env 前,其最后成员 CPUNegativeOffsetState neg 就刚好位于 env 前面。这个设计,有助于二进制转译后的加速优化,直接通过 env 指针的加减就可以访问对应的成员。后面遇到这使用情况再详细说明。

        另外,该设计也有如下使用方式:

static inline CPUArchState *cpu_env(CPUState *cpu)
{/* We validate that CPUArchState follows CPUState in cpu-target.c */return (CPUArchState *)(cpu + 1);
}/*** env_archcpu(env)* @env: The architecture environment** Return the ArchCPU associated with the environment.*/
static inline ArchCPU *env_archcpu(CPUArchState *env)
{return (void *)env - sizeof(CPUState);
}

        另外,还有就是对应的 RISCVCPUClass,如下:

/*** RISCVCPUClass:* @parent_realize: The parent class' realize handler.* @parent_phases: The parent class' reset phase handlers.** A RISCV CPU model.*/
struct RISCVCPUClass {CPUClass parent_class;DeviceRealize parent_realize;ResettablePhases parent_phases;RISCVCPUDef *def;
};
/*** CPUClass:
...* Represents a CPU family or model.*/
struct CPUClass {
...
/* when TCG is not available, this pointer is NULL */const TCGCPUOps *tcg_ops;
...
};

        其中 tcg_ops 就是 TCG 对特定架构CPU的操作函数,其主要成员如下:

const TCGCPUOps riscv_tcg_ops = {.mttcg_supported = true,.guest_default_memory_order = 0,.initialize = riscv_translate_init,.translate_code = riscv_translate_code,.get_tb_cpu_state = riscv_get_tb_cpu_state,.synchronize_from_tb = riscv_cpu_synchronize_from_tb,.restore_state_to_opc = riscv_restore_state_to_opc,.mmu_index = riscv_cpu_mmu_index,#ifndef CONFIG_USER_ONLY.tlb_fill = riscv_cpu_tlb_fill,.pointer_wrap = riscv_pointer_wrap,.cpu_exec_interrupt = riscv_cpu_exec_interrupt,.cpu_exec_halt = riscv_cpu_has_work,.cpu_exec_reset = cpu_reset,.do_interrupt = riscv_cpu_do_interrupt,.do_transaction_failed = riscv_cpu_do_transaction_failed,.do_unaligned_access = riscv_cpu_do_unaligned_access,.debug_excp_handler = riscv_cpu_debug_excp_handler,.debug_check_breakpoint = riscv_cpu_debug_check_breakpoint,.debug_check_watchpoint = riscv_cpu_debug_check_watchpoint,
#endif /* !CONFIG_USER_ONLY */
};

        在 CPUClass 初始化时定义,如下:

/*{.name = TYPE_RISCV_CPU,.parent = TYPE_CPU,.instance_size = sizeof(RISCVCPU),.instance_align = __alignof(RISCVCPU),// 实例初始化函数,类似 instance constructor..instance_init = riscv_cpu_init,.abstract = true,.class_size = sizeof(RISCVCPUClass),// 类初始化函数,类似 class constructor..class_init = riscv_cpu_common_class_init,.class_base_init = riscv_cpu_class_base_init,
}*/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);ResettableClass *rc = RESETTABLE_CLASS(c);device_class_set_parent_realize(dc, riscv_cpu_realize,&mcc->parent_realize);resettable_class_set_parent_phases(rc, NULL, riscv_cpu_reset_hold, NULL,&mcc->parent_phases);cc->class_by_name = riscv_cpu_class_by_name;cc->dump_state = riscv_cpu_dump_state;cc->set_pc = riscv_cpu_set_pc;cc->get_pc = riscv_cpu_get_pc;cc->gdb_read_register = riscv_cpu_gdb_read_register;cc->gdb_write_register = riscv_cpu_gdb_write_register;cc->gdb_stop_before_watchpoint = true;cc->disas_set_info = riscv_cpu_disas_set_info;
#ifndef CONFIG_USER_ONLYcc->sysemu_ops = &riscv_sysemu_ops;cc->get_arch_id = riscv_get_arch_id;
#endifcc->gdb_arch_name = riscv_gdb_arch_name;
#ifdef CONFIG_TCGcc->tcg_ops = &riscv_tcg_ops;
#endif /* CONFIG_TCG */device_class_set_props(dc, riscv_cpu_properties);
}

        至此,对于 RISCV CPU 在 QEMU 是如何表征有了大致上的了解。后续文章,就会可以继续推进 二进制转译的研究了。敬请期待。

http://www.lryc.cn/news/596969.html

相关文章:

  • Axios 响应拦截器
  • AI 搜索引擎:让信息“长脑子”而不是“堆数据”
  • 【Spring Cloud Gateway 实战系列】基础篇:路由、断言、过滤器、负载均衡深度解析
  • 【服务器】 MCTP Over PCIe 的内容、用途、工作原理及硬件设计注意事项
  • 基于php的校园招聘平台
  • SpringCloudGateWay 使用nacos网关自动负载均衡
  • 二分查找-162.寻找峰值-力扣(LeetCode)
  • 思路探索:当大型语言模型遇见数据分析的现实挑战
  • 统一服务入口——Spring Cloud Gateway
  • 高亮匹配关键词样式highLightMatchString、replaceHTMLChar
  • Effective Python 第15条 不要过分依赖给字典添加条目时所用的顺序
  • CodeBuddy IDE实战:用AI全栈能力快速搭建课程表网页
  • JavaScript HTTP 请求:从老古董到新潮流
  • 在线深凹槽深检测方法都有哪些 —— 激光频率梳 3D 轮廓检测
  • 如何在Pico等Android头显中实现无人机低延迟RTMP全景巡检画面播放
  • 2025年7月份实时最新获取地图边界数据方法,省市区县街道多级联动【文末附实时geoJson数据下载】
  • 从零开始学习Dify-Excel数据可视化(四)
  • 无人机光伏巡检误检率↓78%!陌讯多模态融合算法实战解析
  • 【Android】用 ViewPager2 + Fragment + TabLayout 实现标签页切换
  • Android用户鉴权实现方案深度分析
  • react18更新哪些东西
  • Nginx和Apache的区别
  • Apache PDFBox深入实践
  • Apache JMeter 使用记录踩坑
  • MCP客户端架构与实施
  • Apache POI 介绍与使用指南
  • apache-doris安装兼datax-web配置
  • LNMP-zblog分布式部署
  • 【Unity Shader】Special Effects(十二)Glow 外发光(UI)
  • Unity × RTMP × 头显设备:打造沉浸式工业远控视频系统的完整方案