diff --git a/include/unicorn/s390x.h b/include/unicorn/s390x.h index 7cf3f8c4..68bb0210 100644 --- a/include/unicorn/s390x.h +++ b/include/unicorn/s390x.h @@ -12,6 +12,48 @@ extern "C" { #pragma warning(disable : 4201) #endif +//> S390X CPU +typedef enum uc_cpu_s390x { + UC_CPU_S390X_Z900 = 0, + UC_CPU_S390X_Z900_2, + UC_CPU_S390X_Z900_3, + UC_CPU_S390X_Z800, + UC_CPU_S390X_Z990, + UC_CPU_S390X_Z990_2, + UC_CPU_S390X_Z990_3, + UC_CPU_S390X_Z890, + UC_CPU_S390X_Z990_4, + UC_CPU_S390X_Z890_2, + UC_CPU_S390X_Z990_5, + UC_CPU_S390X_Z890_3, + UC_CPU_S390X_Z9EC, + UC_CPU_S390X_Z9EC_2, + UC_CPU_S390X_Z9BC, + UC_CPU_S390X_Z9EC_3, + UC_CPU_S390X_Z9BC_2, + UC_CPU_S390X_Z10EC, + UC_CPU_S390X_Z10EC_2, + UC_CPU_S390X_Z10BC, + UC_CPU_S390X_Z10EC_3, + UC_CPU_S390X_Z10BC_2, + UC_CPU_S390X_Z196, + UC_CPU_S390X_Z196_2, + UC_CPU_S390X_Z114, + UC_CPU_S390X_ZEC12, + UC_CPU_S390X_ZEC12_2, + UC_CPU_S390X_ZBC12, + UC_CPU_S390X_Z13, + UC_CPU_S390X_Z13_2, + UC_CPU_S390X_Z13S, + UC_CPU_S390X_Z14, + UC_CPU_S390X_Z14_2, + UC_CPU_S390X_Z14ZR1, + UC_CPU_S390X_GEN15A, + UC_CPU_S390X_GEN15B, + UC_CPU_S390X_QEMU, + UC_CPU_S390X_MAX +} uc_cpu_s390x; + //> S390X registers typedef enum uc_s390x_reg { UC_S390X_REG_INVALID = 0, diff --git a/qemu/hw/s390x/s390-skeys.c b/qemu/hw/s390x/s390-skeys.c index 3f943f14..04985d7b 100644 --- a/qemu/hw/s390x/s390-skeys.c +++ b/qemu/hw/s390x/s390-skeys.c @@ -19,34 +19,39 @@ #define S390_SKEYS_SAVE_FLAG_SKEYS 0x02 #define S390_SKEYS_SAVE_FLAG_ERROR 0x04 -#if 0 -S390SKeysState *s390_get_skeys_device(void) -{ - S390SKeysState *ss; +static void s390_skeys_class_init(uc_engine *uc, S390SKeysClass* class); +static void qemu_s390_skeys_class_init(uc_engine *uc, S390SKeysClass* skeyclass); +static void s390_skeys_instance_init(uc_engine *uc, S390SKeysState* ss); +static void qemu_s390_skeys_init(uc_engine *uc, QEMUS390SKeysState *skey); - ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL)); - assert(ss); - return ss; +S390SKeysState *s390_get_skeys_device(uc_engine *uc) +{ + S390CPU *cpu = S390_CPU(uc->cpu); + + return (S390SKeysState*)&cpu->ss; } -void s390_skeys_init(void) +void s390_skeys_init(uc_engine *uc) { - Object *obj; + S390CPU *cpu = S390_CPU(uc->cpu); - obj = object_new(TYPE_QEMU_S390_SKEYS); - object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS, - obj, NULL); - object_unref(obj); + s390_skeys_class_init(uc, &cpu->skey); + qemu_s390_skeys_class_init(uc, &cpu->skey); - qdev_init_nofail(DEVICE(obj)); + s390_skeys_instance_init(uc, (S390SKeysState*)&cpu->ss); + qemu_s390_skeys_init(uc, &cpu->ss); + + cpu->ss.class = &cpu->skey; } -static void qemu_s390_skeys_init(Object *obj) +static void qemu_s390_skeys_init(uc_engine *uc, QEMUS390SKeysState *skeys) { - QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj); - MachineState *machine = MACHINE(qdev_get_machine()); + //QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj); + //MachineState *machine = MACHINE(qdev_get_machine()); - skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE; + //skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE; + // Unicorn: Allow users to configure this value? + skeys->key_count = 0x20000000 / TARGET_PAGE_SIZE; skeys->keydata = g_malloc0(skeys->key_count); } @@ -68,9 +73,9 @@ static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, /* Check for uint64 overflow and access beyond end of key data */ if (start_gfn + count > skeydev->key_count || start_gfn + count < count) { - error_report("Error: Setting storage keys for page beyond the end " - "of memory: gfn=%" PRIx64 " count=%" PRId64, - start_gfn, count); + // error_report("Error: Setting storage keys for page beyond the end " + // "of memory: gfn=%" PRIx64 " count=%" PRId64, + // start_gfn, count); return -EINVAL; } @@ -88,9 +93,9 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, /* Check for uint64 overflow and access beyond end of key data */ if (start_gfn + count > skeydev->key_count || start_gfn + count < count) { - error_report("Error: Getting storage keys for page beyond the end " - "of memory: gfn=%" PRIx64 " count=%" PRId64, - start_gfn, count); + // error_report("Error: Getting storage keys for page beyond the end " + // "of memory: gfn=%" PRIx64 " count=%" PRId64, + // start_gfn, count); return -EINVAL; } @@ -100,183 +105,28 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, return 0; } -static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) +static void qemu_s390_skeys_class_init(uc_engine *uc, S390SKeysClass* skeyclass) { - S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); - DeviceClass *dc = DEVICE_CLASS(oc); + // S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); + // DeviceClass *dc = DEVICE_CLASS(oc); skeyclass->skeys_enabled = qemu_s390_skeys_enabled; skeyclass->get_skeys = qemu_s390_skeys_get; skeyclass->set_skeys = qemu_s390_skeys_set; /* Reason: Internal device (only one skeys device for the whole memory) */ - dc->user_creatable = false; + // dc->user_creatable = false; } -static const TypeInfo qemu_s390_skeys_info = { - .name = TYPE_QEMU_S390_SKEYS, - .parent = TYPE_S390_SKEYS, - .instance_init = qemu_s390_skeys_init, - .instance_size = sizeof(QEMUS390SKeysState), - .class_init = qemu_s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), -}; - -static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, - uint64_t count, Error **errp) +static void s390_skeys_instance_init(uc_engine *uc, S390SKeysState* ss) { - uint64_t curpage = startgfn; - uint64_t maxpage = curpage + count - 1; - - for (; curpage <= maxpage; curpage++) { - uint8_t acc = (*keys & 0xF0) >> 4; - int fp = (*keys & 0x08); - int ref = (*keys & 0x04); - int ch = (*keys & 0x02); - int res = (*keys & 0x01); - - fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d," - " ch=%d, reserved=%d\n", - curpage, *keys, acc, fp, ref, ch, res); - keys++; - } + ss->migration_enabled = true; } -static void s390_storage_keys_save(QEMUFile *f, void *opaque) +static void s390_skeys_class_init(uc_engine *uc, S390SKeysClass* class) { - S390SKeysState *ss = S390_SKEYS(opaque); - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - uint64_t pages_left = ram_size / TARGET_PAGE_SIZE; - uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS; - vaddr cur_gfn = 0; - int error = 0; - uint8_t *buf; + // DeviceClass *dc = DEVICE_CLASS(oc); - if (!skeyclass->skeys_enabled(ss)) { - goto end_stream; - } - - buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); - if (!buf) { - error_report("storage key save could not allocate memory"); - goto end_stream; - } - - /* We only support initial memory. Standby memory is not handled yet. */ - qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS); - qemu_put_be64(f, pages_left); - - while (pages_left) { - read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE); - - if (!error) { - error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf); - if (error) { - /* - * If error: we want to fill the stream with valid data instead - * of stopping early so we pad the stream with 0x00 values and - * use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the - * reading side. - */ - error_report("S390_GET_KEYS error %d", error); - memset(buf, 0, S390_SKEYS_BUFFER_SIZE); - eos = S390_SKEYS_SAVE_FLAG_ERROR; - } - } - - qemu_put_buffer(f, buf, read_count); - cur_gfn += read_count; - pages_left -= read_count; - } - - g_free(buf); -end_stream: - qemu_put_be64(f, eos); + // dc->hotpluggable = false; + // set_bit(DEVICE_CATEGORY_MISC, dc->categories); } - -static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id) -{ - S390SKeysState *ss = S390_SKEYS(opaque); - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - int ret = 0; - - while (!ret) { - ram_addr_t addr; - int flags; - - addr = qemu_get_be64(f); - flags = addr & ~TARGET_PAGE_MASK; - addr &= TARGET_PAGE_MASK; - - switch (flags) { - case S390_SKEYS_SAVE_FLAG_SKEYS: { - const uint64_t total_count = qemu_get_be64(f); - uint64_t handled_count = 0, cur_count; - uint64_t cur_gfn = addr / TARGET_PAGE_SIZE; - uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); - - if (!buf) { - error_report("storage key load could not allocate memory"); - ret = -ENOMEM; - break; - } - - while (handled_count < total_count) { - cur_count = MIN(total_count - handled_count, - S390_SKEYS_BUFFER_SIZE); - qemu_get_buffer(f, buf, cur_count); - - ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf); - if (ret < 0) { - error_report("S390_SET_KEYS error %d", ret); - break; - } - handled_count += cur_count; - cur_gfn += cur_count; - } - g_free(buf); - break; - } - case S390_SKEYS_SAVE_FLAG_ERROR: { - error_report("Storage key data is incomplete"); - ret = -EINVAL; - break; - } - case S390_SKEYS_SAVE_FLAG_EOS: - /* normal exit */ - return 0; - default: - error_report("Unexpected storage key flag data: %#x", flags); - ret = -EINVAL; - } - } - - return ret; -} - -static void s390_skeys_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->hotpluggable = false; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo s390_skeys_info = { - .name = TYPE_S390_SKEYS, - .parent = TYPE_DEVICE, - .instance_init = NULL, - .instance_size = sizeof(S390SKeysState), - .class_init = s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), - .abstract = true, -}; - -static void qemu_s390_skeys_register_types(void) -{ - type_register_static(&s390_skeys_info); - type_register_static(&qemu_s390_skeys_info); -} - -type_init(qemu_s390_skeys_register_types) -#endif diff --git a/qemu/include/hw/s390x/storage-keys.h b/qemu/include/hw/s390x/storage-keys.h index 427b6774..811d616e 100644 --- a/qemu/include/hw/s390x/storage-keys.h +++ b/qemu/include/hw/s390x/storage-keys.h @@ -12,6 +12,8 @@ #ifndef S390_STORAGE_KEYS_H #define S390_STORAGE_KEYS_H +#include "uc_priv.h" + /* #define TYPE_S390_SKEYS "s390-skeys" #define S390_SKEYS(obj) \ @@ -23,7 +25,8 @@ */ typedef struct S390SKeysState { - CPUState parent_obj; + //CPUState parent_obj; + bool migration_enabled; // Unicorn: Dummy struct member } S390SKeysState; /* @@ -36,11 +39,11 @@ typedef struct S390SKeysState { #define S390_SKEYS_GET_CLASS(obj) \ OBJECT_GET_CLASS(S390SKeysClass, (obj), TYPE_S390_SKEYS) */ -#define S390_SKEYS_GET_CLASS(obj) (&((S390CPU *)obj)->skey) +#define S390_SKEYS_GET_CLASS(obj) (((QEMUS390SKeysState *)obj)->class) typedef struct S390SKeysClass { - CPUClass parent_class; + //CPUClass parent_class; int (*skeys_enabled)(S390SKeysState *ks); int (*get_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count, uint8_t *keys); @@ -50,17 +53,21 @@ typedef struct S390SKeysClass { #define TYPE_KVM_S390_SKEYS "s390-skeys-kvm" #define TYPE_QEMU_S390_SKEYS "s390-skeys-qemu" +// #define QEMU_S390_SKEYS(obj) \ +// OBJECT_CHECK(QEMUS390SKeysState, (obj), TYPE_QEMU_S390_SKEYS) #define QEMU_S390_SKEYS(obj) \ - OBJECT_CHECK(QEMUS390SKeysState, (obj), TYPE_QEMU_S390_SKEYS) - + (QEMUS390SKeysState*)(obj) typedef struct QEMUS390SKeysState { S390SKeysState parent_obj; uint8_t *keydata; uint32_t key_count; + + // Unicorn + S390SKeysClass *class; } QEMUS390SKeysState; -void s390_skeys_init(void); +void s390_skeys_init(uc_engine *uc); -S390SKeysState *s390_get_skeys_device(void); +S390SKeysState *s390_get_skeys_device(uc_engine *uc); #endif /* S390_STORAGE_KEYS_H */ diff --git a/qemu/target/s390x/cpu.c b/qemu/target/s390x/cpu.c index 9573cb27..dd824580 100644 --- a/qemu/target/s390x/cpu.c +++ b/qemu/target/s390x/cpu.c @@ -137,6 +137,8 @@ static void s390_cpu_initfn(struct uc_struct *uc, CPUState *obj) // cpu->env.cpu_timer = // timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); + + cpu->env.uc = uc; } static unsigned s390_count_running_cpus(void) @@ -255,6 +257,13 @@ S390CPU *cpu_s390_init(struct uc_struct *uc, const char *cpu_model) return NULL; } + if (uc->cpu_model == INT_MAX) { + uc->cpu_model = 36; // qemu-s390x-cpu + } else if (uc->cpu_model >= 38) { + free(cpu); + return NULL; + } + cs = (CPUState *)cpu; cc = (CPUClass *)&cpu->cc; cs->cc = cc; @@ -267,29 +276,18 @@ S390CPU *cpu_s390_init(struct uc_struct *uc, const char *cpu_model) /* init CPUClass */ s390_cpu_class_init(uc, cc); + // init skeys + s390_skeys_init(uc); + + // init s390 models + s390_init_cpu_model(uc, uc->cpu_model); + /* init CPUState */ cpu_common_initfn(uc, cs); /* init CPU */ s390_cpu_initfn(uc, cs); - /* init specific CPU model */ -/* - for (i = 0; i < ARRAY_SIZE(cpu_models); i++) { - if (strcmp(cpu_model, cpu_models[i].name) == 0) { - cpu_models[i].initfn(cs); - - if (arm_cpus[i].class_init) { - arm_cpus[i].class_init(uc, cc, uc); - } - if (arm_cpus[i].initfn) { - arm_cpus[i].initfn(uc, cs); - } - break; - } - } -*/ - /* realize CPU */ s390_cpu_realizefn(uc, cs); diff --git a/qemu/target/s390x/cpu.h b/qemu/target/s390x/cpu.h index 2548d653..368b0ef7 100644 --- a/qemu/target/s390x/cpu.h +++ b/qemu/target/s390x/cpu.h @@ -166,6 +166,7 @@ struct S390CPU { // unicorn struct S390CPUClass cc; struct S390SKeysClass skey; + struct QEMUS390SKeysState ss; }; diff --git a/qemu/target/s390x/cpu_models.c b/qemu/target/s390x/cpu_models.c index a9bc83f7..37192fe0 100644 --- a/qemu/target/s390x/cpu_models.c +++ b/qemu/target/s390x/cpu_models.c @@ -409,7 +409,7 @@ static void s390_max_cpu_model_initfn(CPUState *obj) memcpy(cpu->model, max_model, sizeof(*cpu->model)); } -static void s390_cpu_model_finalize(CPUState *obj) +void s390_cpu_model_finalize(CPUState *obj) { S390CPU *cpu = S390_CPU(obj); @@ -424,7 +424,7 @@ static void s390_base_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, v /* all base models are migration safe */ xcc->cpu_def = (const S390CPUDef *) data; xcc->is_static = true; - //xcc->desc = xcc->cpu_def->desc; + // xcc->desc = xcc->cpu_def->desc; } static void s390_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void *data) @@ -433,7 +433,8 @@ static void s390_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void * /* model that can change between QEMU versions */ xcc->cpu_def = (const S390CPUDef *) data; - //xcc->desc = xcc->cpu_def->desc; + // xcc->is_migration_safe = true; + // xcc->desc = xcc->cpu_def->desc; } static void s390_qemu_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void *data) @@ -524,9 +525,8 @@ static void init_ignored_base_feat(void) } } -static void register_types(void) +void s390_init_cpu_model(uc_engine *uc, uc_cpu_s390x cpu_model) { -#if 0 static const S390FeatInit qemu_latest_init = { S390_FEAT_LIST_QEMU_LATEST }; int i; @@ -547,33 +547,16 @@ static void register_types(void) s390_set_qemu_cpu_model(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN, QEMU_MAX_CPU_EC_GA, qemu_latest_init); - for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { - char *base_name = s390_base_cpu_type_name(s390_cpu_defs[i].name); - TypeInfo ti_base = { - .name = base_name, - .parent = TYPE_S390_CPU, - .instance_init = s390_cpu_model_initfn, - .instance_finalize = s390_cpu_model_finalize, - .class_init = s390_base_cpu_model_class_init, - .class_data = (void *) &s390_cpu_defs[i], - }; - char *name = s390_cpu_type_name(s390_cpu_defs[i].name); - TypeInfo ti = { - .name = name, - .parent = TYPE_S390_CPU, - .instance_init = s390_cpu_model_initfn, - .instance_finalize = s390_cpu_model_finalize, - .class_init = s390_cpu_model_class_init, - .class_data = (void *) &s390_cpu_defs[i], - }; - - type_register_static(&ti_base); - type_register_static(&ti); - g_free(base_name); - g_free(name); + if (cpu_model < ARRAY_SIZE(s390_cpu_defs)) { + s390_base_cpu_model_class_init(uc, uc->cpu->cc, (void *) &s390_cpu_defs[cpu_model]); + s390_cpu_model_class_init(uc, uc->cpu->cc, (void *) &s390_cpu_defs[cpu_model]); + s390_cpu_model_initfn(uc->cpu); + } else if (cpu_model == UC_CPU_S390X_MAX) { + s390_max_cpu_model_class_init(uc, uc->cpu->cc, NULL); + s390_max_cpu_model_initfn(uc->cpu); + } else if (cpu_model == UC_CPU_S390X_QEMU) { + s390_qemu_cpu_model_class_init(uc, uc->cpu->cc, NULL); + s390_qemu_cpu_model_initfn(uc->cpu); } - type_register_static(&qemu_s390_cpu_type_info); - type_register_static(&max_s390_cpu_type_info); -#endif } diff --git a/qemu/target/s390x/cpu_models.h b/qemu/target/s390x/cpu_models.h index 23e53796..be3655ab 100644 --- a/qemu/target/s390x/cpu_models.h +++ b/qemu/target/s390x/cpu_models.h @@ -16,6 +16,8 @@ #include "cpu_features.h" #include "gen-features.h" #include "hw/core/cpu.h" +#include "unicorn/s390x.h" +#include "uc_priv.h" /* static CPU definition */ struct S390CPUDef { @@ -106,4 +108,8 @@ static inline uint64_t s390_cpuid_from_cpu_model(const S390CPUModel *model) S390CPUDef const *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, S390FeatBitmap features); +void s390_init_cpu_model(uc_engine *uc, uc_cpu_s390x cpu_model); + +void s390_cpu_model_finalize(CPUState *obj); + #endif /* TARGET_S390X_CPU_MODELS_H */ diff --git a/qemu/target/s390x/mmu_helper.c b/qemu/target/s390x/mmu_helper.c index f9dc73e8..829dec55 100644 --- a/qemu/target/s390x/mmu_helper.c +++ b/qemu/target/s390x/mmu_helper.c @@ -282,7 +282,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, return 0; } -static void mmu_handle_skey(target_ulong addr, int rw, int *flags) +static void mmu_handle_skey(uc_engine *uc, target_ulong addr, int rw, int *flags) { static S390SKeysClass *skeyclass; static S390SKeysState *ss; @@ -296,8 +296,8 @@ static void mmu_handle_skey(target_ulong addr, int rw, int *flags) #endif if (unlikely(!ss)) { - // ss = s390_get_skeys_device(); - // skeyclass = S390_SKEYS_GET_CLASS(ss); + ss = s390_get_skeys_device(uc); + skeyclass = S390_SKEYS_GET_CLASS(ss); } /* @@ -437,7 +437,7 @@ nodat: /* Convert real address -> absolute address */ *raddr = mmu_real2abs(env, *raddr); - mmu_handle_skey(*raddr, rw, flags); + mmu_handle_skey(env->uc, *raddr, rw, flags); return 0; } @@ -549,6 +549,6 @@ int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw, *addr = mmu_real2abs(env, raddr & TARGET_PAGE_MASK); - mmu_handle_skey(*addr, rw, flags); + mmu_handle_skey(env->uc, *addr, rw, flags); return 0; } diff --git a/qemu/target/s390x/unicorn.c b/qemu/target/s390x/unicorn.c index df9731ec..5f1ace7f 100644 --- a/qemu/target/s390x/unicorn.c +++ b/qemu/target/s390x/unicorn.c @@ -33,6 +33,13 @@ static void s390_release(void *ctx) g_free(fast->table); } #endif + TCGContext *tcg_ctx = (TCGContext *)ctx; + S390CPU *cpu = (S390CPU *)tcg_ctx->uc->cpu; + + release_common(ctx); + + s390_cpu_model_finalize(cpu); + // TODO: Anymore to free? } void s390_reg_reset(struct uc_struct *uc)