@@ -99,6 +99,31 @@ static const struct TCGCPUOps riscv_tcg_ops = {
#endif /* !CONFIG_USER_ONLY */
};
+static const char *cpu_get_multi_ext_cfg_name(uint32_t ext_offset)
+{
+ const RISCVCPUMultiExtConfig *prop;
+
+ for (prop = riscv_cpu_extensions; prop && prop->name; prop++) {
+ if (prop->offset == ext_offset) {
+ return prop->name;
+ }
+ }
+
+ for (prop = riscv_cpu_experimental_exts; prop && prop->name; prop++) {
+ if (prop->offset == ext_offset) {
+ return prop->name;
+ }
+ }
+
+ for (prop = riscv_cpu_vendor_exts; prop && prop->name; prop++) {
+ if (prop->offset == ext_offset) {
+ return prop->name;
+ }
+ }
+
+ return NULL;
+}
+
static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
{
const RISCVIsaExtData *edata;
@@ -747,7 +772,7 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name,
RISCVCPU *cpu = RISCV_CPU(obj);
CPURISCVState *env = &cpu->env;
int i = 0;
- bool value;
+ bool value, generic_cpu;
if (!visit_type_bool(v, name, &value, errp)) {
return;
@@ -758,16 +783,28 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name,
return;
}
+ generic_cpu = object_dynamic_cast(obj, TYPE_RISCV_DYNAMIC_CPU) != NULL;
+
env->misa_ext |= profile->misa_ext;
env->misa_ext_mask |= profile->misa_ext;
for (i = 0;; i++) {
int ext_offset = profile->ext_offsets[i];
+ bool prev_val = isa_ext_is_enabled(cpu, ext_offset);
if (ext_offset == RISCV_PROFILE_EXT_LIST_END) {
break;
}
+ if (!prev_val && !generic_cpu) {
+ const char *ext_name = cpu_get_multi_ext_cfg_name(ext_offset);
+ const char *cpu_name = riscv_cpu_get_name(cpu);
+
+ error_setg(errp, "Setting profile '%s' failed: CPU %s does not "
+ "support extension '%s'", name, cpu_name, ext_name);
+ return;
+ }
+
isa_ext_update_enabled(cpu, ext_offset, true);
g_hash_table_insert(multi_ext_user_opts,
GUINT_TO_POINTER(ext_offset),
@@ -885,9 +922,7 @@ static void riscv_cpu_add_user_properties(Object *obj)
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts);
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts);
- if (object_dynamic_cast(obj, TYPE_RISCV_DYNAMIC_CPU) != NULL) {
- riscv_cpu_add_profile_prop(obj, &RVA22U64);
- }
+ riscv_cpu_add_profile_prop(obj, &RVA22U64);
for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) {
qdev_property_add_static(DEVICE(obj), prop);
Vendor CPUs can implement any profile they want as long as all required extensions are being set in their respective cpu_init(). We do not enable extensions for vendor CPUs and that will still be true with profile support. The idea then is to enable the profile option for vendor CPUs and let users try to enable it. In case the vendor CPU do not implement all mandatory extensions of the profile, error out. Proceed as usual otherwise. Here's an example of what happens if we try to enable the rva22u64 profile with the veyron-v1 CPU: ./qemu-system-riscv64 -M virt -cpu veyron-v1,rva22u64=true qemu-system-riscv64: can't apply global veyron-v1-riscv-cpu.rva22u64=true: Setting profile 'rva22u64' failed: CPU veyron-v1 does not support extension 'Zihintpause' Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> --- target/riscv/tcg/tcg-cpu.c | 43 ++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-)