s390x updates:

- add gen16 cpumodels
 - refactor/cleanup some code
 - bugfixes
 -----BEGIN PGP SIGNATURE-----
 
 iIgEABYIADAWIQRpo7U29cv8ZSCAJsHeiLtWQd5mwQUCYObg3RIcY29odWNrQHJl
 ZGhhdC5jb20ACgkQ3oi7VkHeZsGAdAD/dSZkhfgjNWJjka0hmnyQyNCSzq6jox1L
 PccGyqhkqU8BAM4DUa2bZdst8bLfhUuAA0M5gKkCqkzHdDraBqTL8LQJ
 =H7dn
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cohuck-gitlab/tags/s390x-20210708' into staging

s390x updates:
- add gen16 cpumodels
- refactor/cleanup some code
- bugfixes

# gpg: Signature made Thu 08 Jul 2021 12:26:21 BST
# gpg:                using EDDSA key 69A3B536F5CBFC65208026C1DE88BB5641DE66C1
# gpg:                issuer "cohuck@redhat.com"
# gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" [unknown]
# gpg:                 aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" [full]
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>" [full]
# gpg:                 aka "Cornelia Huck <cohuck@kernel.org>" [unknown]
# gpg:                 aka "Cornelia Huck <cohuck@redhat.com>" [unknown]
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF
#      Subkey fingerprint: 69A3 B536 F5CB FC65 2080  26C1 DE88 BB56 41DE 66C1

* remotes/cohuck-gitlab/tags/s390x-20210708:
  target/s390x: split sysemu part of cpu models
  target/s390x: move kvm files into kvm/
  target/s390x: remove kvm-stub.c
  target/s390x: use kvm_enabled() to wrap call to kvm_s390_get_hpage_1m
  target/s390x: make helper.c sysemu-only
  target/s390x: split cpu-dump from helper.c
  target/s390x: move sysemu-only code out to cpu-sysemu.c
  target/s390x: start moving TCG-only code to tcg/
  target/s390x: rename internal.h to s390x-internal.h
  target/s390x: remove tcg-stub.c
  hw/s390x: only build tod-tcg from the CONFIG_TCG build
  hw/s390x: tod: make explicit checks for accelerators when initializing
  hw/s390x: rename tod-qemu.c to tod-tcg.c
  target/s390x: meson: add target_user_arch
  s390x/tcg: Fix m5 vs. m4 field for VECTOR MULTIPLY SUM LOGICAL
  target/s390x: Fix CC set by CONVERT TO FIXED/LOGICAL
  s390x/cpumodel: add 3931 and 3932

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-07-12 19:15:11 +01:00
commit 57e28d34c0
57 changed files with 1168 additions and 1128 deletions

View file

@ -297,6 +297,8 @@ M: Richard Henderson <richard.henderson@linaro.org>
M: David Hildenbrand <david@redhat.com>
S: Maintained
F: target/s390x/
F: target/s390x/tcg
F: target/s390x/cpu_models_*.[ch]
F: hw/s390x/
F: disas/s390.c
F: tests/tcg/s390x/
@ -393,9 +395,7 @@ M: Halil Pasic <pasic@linux.ibm.com>
M: Cornelia Huck <cohuck@redhat.com>
M: Christian Borntraeger <borntraeger@de.ibm.com>
S: Supported
F: target/s390x/kvm.c
F: target/s390x/kvm_s390x.h
F: target/s390x/kvm-stub.c
F: target/s390x/kvm/
F: target/s390x/ioinst.[ch]
F: target/s390x/machine.c
F: target/s390x/sigp.c

View file

@ -11,7 +11,7 @@
*/
#include "qemu/osdep.h"
#include "kvm_s390x.h"
#include "kvm/kvm_s390x.h"
#include <sys/ioctl.h>
#include "qemu/error-report.h"
#include "qemu/module.h"

View file

@ -16,7 +16,6 @@ s390x_ss.add(files(
'sclp.c',
'sclpcpu.c',
'sclpquiesce.c',
'tod-qemu.c',
'tod.c',
))
s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
@ -25,6 +24,9 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
's390-stattrib-kvm.c',
'pv.c',
))
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
'tod-tcg.c',
))
s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files('s390-virtio-ccw.c'))
s390x_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('3270-ccw.c'))
s390x_ss.add(when: 'CONFIG_VFIO', if_true: files('s390-pci-vfio.c'))

View file

@ -16,7 +16,7 @@
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
#include "exec/ram_addr.h"
#include "kvm_s390x.h"
#include "kvm/kvm_s390x.h"
Object *kvm_s390_stattrib_create(void)
{

View file

@ -13,7 +13,7 @@
#include "qemu/module.h"
#include "sysemu/runstate.h"
#include "hw/s390x/tod.h"
#include "kvm_s390x.h"
#include "kvm/kvm_s390x.h"
static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp)
{

View file

@ -1,5 +1,5 @@
/*
* TOD (Time Of Day) clock - QEMU implementation
* TOD (Time Of Day) clock - TCG implementation
*
* Copyright 2018 Red Hat, Inc.
* Author(s): David Hildenbrand <david@redhat.com>
@ -16,7 +16,7 @@
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "cpu.h"
#include "tcg_s390x.h"
#include "tcg/tcg_s390x.h"
static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
Error **errp)

View file

@ -14,6 +14,8 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "sysemu/qtest.h"
#include "migration/qemu-file-types.h"
#include "migration/register.h"
@ -23,8 +25,13 @@ void s390_init_tod(void)
if (kvm_enabled()) {
obj = object_new(TYPE_KVM_S390_TOD);
} else {
} else if (tcg_enabled()) {
obj = object_new(TYPE_QEMU_S390_TOD);
} else if (qtest_enabled()) {
return;
} else {
error_report("current accelerator not handled in s390_init_tod!");
abort();
}
object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj);
object_unref(obj);

View file

@ -21,7 +21,7 @@
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "kvm_s390x.h"
#include "kvm/kvm_s390x.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/ap-bridge.h"

View file

@ -12,7 +12,7 @@
#define HW_S390_TOD_H
#include "hw/qdev-core.h"
#include "target/s390x/s390-tod.h"
#include "tcg/s390-tod.h"
#include "qom/object.h"
typedef struct S390TOD {

View file

@ -2123,6 +2123,7 @@ if have_system or have_user
'target/ppc',
'target/riscv',
'target/s390x',
'target/s390x/kvm',
'target/sparc',
]
endif

View file

@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "elf.h"
#include "sysemu/dump.h"

134
target/s390x/cpu-dump.c Normal file
View file

@ -0,0 +1,134 @@
/*
* S/390 CPU dump to FILE
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "s390x-internal.h"
#include "qemu/qemu-print.h"
#include "sysemu/tcg.h"
void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
int i;
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64,
s390_cpu_get_psw_mask(env), env->psw.addr);
if (!tcg_enabled()) {
qemu_fprintf(f, "\n");
} else if (env->cc_op > 3) {
qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op));
} else {
qemu_fprintf(f, " cc %02x\n", env->cc_op);
}
for (i = 0; i < 16; i++) {
qemu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
if ((i % 4) == 3) {
qemu_fprintf(f, "\n");
} else {
qemu_fprintf(f, " ");
}
}
if (flags & CPU_DUMP_FPU) {
if (s390_has_feat(S390_FEAT_VECTOR)) {
for (i = 0; i < 32; i++) {
qemu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64 "%c",
i, env->vregs[i][0], env->vregs[i][1],
i % 2 ? '\n' : ' ');
}
} else {
for (i = 0; i < 16; i++) {
qemu_fprintf(f, "F%02d=%016" PRIx64 "%c",
i, *get_freg(env, i),
(i % 4) == 3 ? '\n' : ' ');
}
}
}
#ifndef CONFIG_USER_ONLY
for (i = 0; i < 16; i++) {
qemu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
if ((i % 4) == 3) {
qemu_fprintf(f, "\n");
} else {
qemu_fprintf(f, " ");
}
}
#endif
#ifdef DEBUG_INLINE_BRANCHES
for (i = 0; i < CC_OP_MAX; i++) {
qemu_fprintf(f, " %15s = %10ld\t%10ld\n", cc_name(i),
inline_branch_miss[i], inline_branch_hit[i]);
}
#endif
qemu_fprintf(f, "\n");
}
const char *cc_name(enum cc_op cc_op)
{
static const char * const cc_names[] = {
[CC_OP_CONST0] = "CC_OP_CONST0",
[CC_OP_CONST1] = "CC_OP_CONST1",
[CC_OP_CONST2] = "CC_OP_CONST2",
[CC_OP_CONST3] = "CC_OP_CONST3",
[CC_OP_DYNAMIC] = "CC_OP_DYNAMIC",
[CC_OP_STATIC] = "CC_OP_STATIC",
[CC_OP_NZ] = "CC_OP_NZ",
[CC_OP_ADDU] = "CC_OP_ADDU",
[CC_OP_SUBU] = "CC_OP_SUBU",
[CC_OP_LTGT_32] = "CC_OP_LTGT_32",
[CC_OP_LTGT_64] = "CC_OP_LTGT_64",
[CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
[CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
[CC_OP_LTGT0_32] = "CC_OP_LTGT0_32",
[CC_OP_LTGT0_64] = "CC_OP_LTGT0_64",
[CC_OP_ADD_64] = "CC_OP_ADD_64",
[CC_OP_SUB_64] = "CC_OP_SUB_64",
[CC_OP_ABS_64] = "CC_OP_ABS_64",
[CC_OP_NABS_64] = "CC_OP_NABS_64",
[CC_OP_ADD_32] = "CC_OP_ADD_32",
[CC_OP_SUB_32] = "CC_OP_SUB_32",
[CC_OP_ABS_32] = "CC_OP_ABS_32",
[CC_OP_NABS_32] = "CC_OP_NABS_32",
[CC_OP_COMP_32] = "CC_OP_COMP_32",
[CC_OP_COMP_64] = "CC_OP_COMP_64",
[CC_OP_TM_32] = "CC_OP_TM_32",
[CC_OP_TM_64] = "CC_OP_TM_64",
[CC_OP_NZ_F32] = "CC_OP_NZ_F32",
[CC_OP_NZ_F64] = "CC_OP_NZ_F64",
[CC_OP_NZ_F128] = "CC_OP_NZ_F128",
[CC_OP_ICM] = "CC_OP_ICM",
[CC_OP_SLA_32] = "CC_OP_SLA_32",
[CC_OP_SLA_64] = "CC_OP_SLA_64",
[CC_OP_FLOGR] = "CC_OP_FLOGR",
[CC_OP_LCBB] = "CC_OP_LCBB",
[CC_OP_VC] = "CC_OP_VC",
[CC_OP_MULS_32] = "CC_OP_MULS_32",
[CC_OP_MULS_64] = "CC_OP_MULS_64",
};
return cc_names[cc_op];
}

309
target/s390x/cpu-sysemu.c Normal file
View file

@ -0,0 +1,309 @@
/*
* QEMU S/390 CPU - System Emulation-only code
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf
* Copyright (c) 2012 SUSE LINUX Products GmbH
* Copyright (c) 2012 IBM Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#include "s390x-internal.h"
#include "kvm/kvm_s390x.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
#include "qemu/timer.h"
#include "trace.h"
#include "qapi/qapi-visit-run-state.h"
#include "sysemu/hw_accel.h"
#include "hw/s390x/pv.h"
#include "hw/boards.h"
#include "sysemu/arch_init.h"
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "hw/core/sysemu-cpu-ops.h"
/* S390CPUClass::load_normal() */
static void s390_cpu_load_normal(CPUState *s)
{
S390CPU *cpu = S390_CPU(s);
uint64_t spsw;
if (!s390_is_pv()) {
spsw = ldq_phys(s->as, 0);
cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
/*
* Invert short psw indication, so SIE will report a specification
* exception if it was not set.
*/
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
} else {
/*
* Firmware requires us to set the load state before we set
* the cpu to operating on protected guests.
*/
s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
}
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
}
void s390_cpu_machine_reset_cb(void *opaque)
{
S390CPU *cpu = opaque;
run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
}
static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
{
GuestPanicInformation *panic_info;
S390CPU *cpu = S390_CPU(cs);
cpu_synchronize_state(cs);
panic_info = g_malloc0(sizeof(GuestPanicInformation));
panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
panic_info->u.s390.core = cpu->env.core_id;
panic_info->u.s390.psw_mask = cpu->env.psw.mask;
panic_info->u.s390.psw_addr = cpu->env.psw.addr;
panic_info->u.s390.reason = cpu->env.crash_reason;
return panic_info;
}
static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
CPUState *cs = CPU(obj);
GuestPanicInformation *panic_info;
if (!cs->crash_occurred) {
error_setg(errp, "No crash occurred");
return;
}
panic_info = s390_cpu_get_crash_info(cs);
visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
errp);
qapi_free_GuestPanicInformation(panic_info);
}
void s390_cpu_init_sysemu(Object *obj)
{
CPUState *cs = CPU(obj);
S390CPU *cpu = S390_CPU(obj);
cs->start_powered_off = true;
object_property_add(obj, "crash-information", "GuestPanicInformation",
s390_cpu_get_crash_info_qom, NULL, NULL, NULL);
cpu->env.tod_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
cpu->env.cpu_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
}
bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp)
{
S390CPU *cpu = S390_CPU(dev);
MachineState *ms = MACHINE(qdev_get_machine());
unsigned int max_cpus = ms->smp.max_cpus;
if (cpu->env.core_id >= max_cpus) {
error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
", maximum core-id: %d", cpu->env.core_id,
max_cpus - 1);
return false;
}
if (cpu_exists(cpu->env.core_id)) {
error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
", it already exists", cpu->env.core_id);
return false;
}
/* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
CPU(cpu)->cpu_index = cpu->env.core_id;
return true;
}
void s390_cpu_finalize(Object *obj)
{
S390CPU *cpu = S390_CPU(obj);
timer_free(cpu->env.tod_timer);
timer_free(cpu->env.cpu_timer);
qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
g_free(cpu->irqstate);
}
static const struct SysemuCPUOps s390_sysemu_ops = {
.get_phys_page_debug = s390_cpu_get_phys_page_debug,
.get_crash_info = s390_cpu_get_crash_info,
.write_elf64_note = s390_cpu_write_elf64_note,
.legacy_vmsd = &vmstate_s390_cpu,
};
void s390_cpu_class_init_sysemu(CPUClass *cc)
{
S390CPUClass *scc = S390_CPU_CLASS(cc);
scc->load_normal = s390_cpu_load_normal;
cc->sysemu_ops = &s390_sysemu_ops;
}
static bool disabled_wait(CPUState *cpu)
{
return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
}
static unsigned s390_count_running_cpus(void)
{
CPUState *cpu;
int nr_running = 0;
CPU_FOREACH(cpu) {
uint8_t state = S390_CPU(cpu)->env.cpu_state;
if (state == S390_CPU_STATE_OPERATING ||
state == S390_CPU_STATE_LOAD) {
if (!disabled_wait(cpu)) {
nr_running++;
}
}
}
return nr_running;
}
unsigned int s390_cpu_halt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
trace_cpu_halt(cs->cpu_index);
if (!cs->halted) {
cs->halted = 1;
cs->exception_index = EXCP_HLT;
}
return s390_count_running_cpus();
}
void s390_cpu_unhalt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
trace_cpu_unhalt(cs->cpu_index);
if (cs->halted) {
cs->halted = 0;
cs->exception_index = -1;
}
}
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
{
trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
switch (cpu_state) {
case S390_CPU_STATE_STOPPED:
case S390_CPU_STATE_CHECK_STOP:
/* halt the cpu for common infrastructure */
s390_cpu_halt(cpu);
break;
case S390_CPU_STATE_OPERATING:
case S390_CPU_STATE_LOAD:
/*
* Starting a CPU with a PSW WAIT bit set:
* KVM: handles this internally and triggers another WAIT exit.
* TCG: will actually try to continue to run. Don't unhalt, will
* be done when the CPU actually has work (an interrupt).
*/
if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
s390_cpu_unhalt(cpu);
}
break;
default:
error_report("Requested CPU state is not a valid S390 CPU state: %u",
cpu_state);
exit(1);
}
if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
kvm_s390_set_cpu_state(cpu, cpu_state);
}
cpu->env.cpu_state = cpu_state;
return s390_count_running_cpus();
}
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
{
if (kvm_enabled()) {
return kvm_s390_set_mem_limit(new_limit, hw_limit);
}
return 0;
}
void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
{
if (kvm_enabled()) {
kvm_s390_set_max_pagesize(pagesize, errp);
}
}
void s390_cmma_reset(void)
{
if (kvm_enabled()) {
kvm_s390_cmma_reset();
}
}
int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
int vq, bool assign)
{
if (kvm_enabled()) {
return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
} else {
return 0;
}
}
void s390_crypto_reset(void)
{
if (kvm_enabled()) {
kvm_s390_crypto_reset();
}
}
void s390_enable_css_support(S390CPU *cpu)
{
if (kvm_enabled()) {
kvm_s390_enable_css_support(cpu);
}
}
void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
{
if (kvm_enabled()) {
kvm_s390_set_diag318(cs, arg.host_ulong);
}
}

View file

@ -23,31 +23,64 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#include "internal.h"
#include "kvm_s390x.h"
#include "s390x-internal.h"
#include "kvm/kvm_s390x.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "trace.h"
#include "qapi/visitor.h"
#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-visit-run-state.h"
#include "sysemu/hw_accel.h"
#include "hw/qdev-properties.h"
#ifndef CONFIG_USER_ONLY
#include "hw/s390x/pv.h"
#include "hw/boards.h"
#include "sysemu/arch_init.h"
#include "sysemu/tcg.h"
#endif
#include "fpu/softfloat-helpers.h"
#include "disas/capstone.h"
#include "sysemu/tcg.h"
#define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL;
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
#ifndef CONFIG_USER_ONLY
uint64_t old_mask = env->psw.mask;
#endif
env->psw.addr = addr;
env->psw.mask = mask;
/* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
if (!tcg_enabled()) {
return;
}
env->cc_op = (mask >> 44) & 3;
#ifndef CONFIG_USER_ONLY
if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(env_cpu(env));
}
if (mask & PSW_MASK_WAIT) {
s390_handle_wait(env_archcpu(env));
}
#endif
}
uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
{
uint64_t r = env->psw.mask;
if (tcg_enabled()) {
uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
env->cc_dst, env->cc_vr);
assert(cc <= 3);
r &= ~PSW_MASK_CC;
r |= cc << 44;
}
return r;
}
static void s390_cpu_set_pc(CPUState *cs, vaddr value)
{
S390CPU *cpu = S390_CPU(cs);
@ -72,33 +105,6 @@ static bool s390_cpu_has_work(CPUState *cs)
return s390_cpu_has_int(cpu);
}
#if !defined(CONFIG_USER_ONLY)
/* S390CPUClass::load_normal() */
static void s390_cpu_load_normal(CPUState *s)
{
S390CPU *cpu = S390_CPU(s);
uint64_t spsw;
if (!s390_is_pv()) {
spsw = ldq_phys(s->as, 0);
cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
/*
* Invert short psw indication, so SIE will report a specification
* exception if it was not set.
*/
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
} else {
/*
* Firmware requires us to set the load state before we set
* the cpu to operating on protected guests.
*/
s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
}
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
}
#endif
/* S390CPUClass::reset() */
static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
{
@ -169,15 +175,6 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
}
}
#if !defined(CONFIG_USER_ONLY)
static void s390_cpu_machine_reset_cb(void *opaque)
{
S390CPU *cpu = opaque;
run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
}
#endif
static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
{
info->mach = bfd_mach_s390_64;
@ -191,9 +188,6 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
#if !defined(CONFIG_USER_ONLY)
S390CPU *cpu = S390_CPU(dev);
#endif
Error *err = NULL;
/* the model has to be realized before qemu_init_vcpu() due to kvm */
@ -203,23 +197,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
}
#if !defined(CONFIG_USER_ONLY)
MachineState *ms = MACHINE(qdev_get_machine());
unsigned int max_cpus = ms->smp.max_cpus;
if (cpu->env.core_id >= max_cpus) {
error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
", maximum core-id: %d", cpu->env.core_id,
max_cpus - 1);
if (!s390_cpu_realize_sysemu(dev, &err)) {
goto out;
}
if (cpu_exists(cpu->env.core_id)) {
error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
", it already exists", cpu->env.core_id);
goto out;
}
/* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
cs->cpu_index = cpu->env.core_id;
#endif
cpu_exec_realizefn(cs, &err);
@ -228,7 +208,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
}
#if !defined(CONFIG_USER_ONLY)
qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
qemu_register_reset(s390_cpu_machine_reset_cb, S390_CPU(dev));
#endif
s390_cpu_gdb_init(cs);
qemu_init_vcpu(cs);
@ -250,44 +230,6 @@ out:
error_propagate(errp, err);
}
#if !defined(CONFIG_USER_ONLY)
static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
{
GuestPanicInformation *panic_info;
S390CPU *cpu = S390_CPU(cs);
cpu_synchronize_state(cs);
panic_info = g_malloc0(sizeof(GuestPanicInformation));
panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
panic_info->u.s390.core = cpu->env.core_id;
panic_info->u.s390.psw_mask = cpu->env.psw.mask;
panic_info->u.s390.psw_addr = cpu->env.psw.addr;
panic_info->u.s390.reason = cpu->env.crash_reason;
return panic_info;
}
static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
CPUState *cs = CPU(obj);
GuestPanicInformation *panic_info;
if (!cs->crash_occurred) {
error_setg(errp, "No crash occurred");
return;
}
panic_info = s390_cpu_get_crash_info(cs);
visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
errp);
qapi_free_GuestPanicInformation(panic_info);
}
#endif
static void s390_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@ -295,168 +237,11 @@ static void s390_cpu_initfn(Object *obj)
cpu_set_cpustate_pointers(cpu);
cs->exception_index = EXCP_HLT;
#if !defined(CONFIG_USER_ONLY)
cs->start_powered_off = true;
object_property_add(obj, "crash-information", "GuestPanicInformation",
s390_cpu_get_crash_info_qom, NULL, NULL, NULL);
cpu->env.tod_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
cpu->env.cpu_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
#endif
}
static void s390_cpu_finalize(Object *obj)
{
#if !defined(CONFIG_USER_ONLY)
S390CPU *cpu = S390_CPU(obj);
timer_free(cpu->env.tod_timer);
timer_free(cpu->env.cpu_timer);
qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
g_free(cpu->irqstate);
#endif
}
#if !defined(CONFIG_USER_ONLY)
static bool disabled_wait(CPUState *cpu)
{
return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
}
static unsigned s390_count_running_cpus(void)
{
CPUState *cpu;
int nr_running = 0;
CPU_FOREACH(cpu) {
uint8_t state = S390_CPU(cpu)->env.cpu_state;
if (state == S390_CPU_STATE_OPERATING ||
state == S390_CPU_STATE_LOAD) {
if (!disabled_wait(cpu)) {
nr_running++;
}
}
}
return nr_running;
}
unsigned int s390_cpu_halt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
trace_cpu_halt(cs->cpu_index);
if (!cs->halted) {
cs->halted = 1;
cs->exception_index = EXCP_HLT;
}
return s390_count_running_cpus();
}
void s390_cpu_unhalt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
trace_cpu_unhalt(cs->cpu_index);
if (cs->halted) {
cs->halted = 0;
cs->exception_index = -1;
}
}
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
{
trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
switch (cpu_state) {
case S390_CPU_STATE_STOPPED:
case S390_CPU_STATE_CHECK_STOP:
/* halt the cpu for common infrastructure */
s390_cpu_halt(cpu);
break;
case S390_CPU_STATE_OPERATING:
case S390_CPU_STATE_LOAD:
/*
* Starting a CPU with a PSW WAIT bit set:
* KVM: handles this internally and triggers another WAIT exit.
* TCG: will actually try to continue to run. Don't unhalt, will
* be done when the CPU actually has work (an interrupt).
*/
if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
s390_cpu_unhalt(cpu);
}
break;
default:
error_report("Requested CPU state is not a valid S390 CPU state: %u",
cpu_state);
exit(1);
}
if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
kvm_s390_set_cpu_state(cpu, cpu_state);
}
cpu->env.cpu_state = cpu_state;
return s390_count_running_cpus();
}
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
{
if (kvm_enabled()) {
return kvm_s390_set_mem_limit(new_limit, hw_limit);
}
return 0;
}
void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
{
if (kvm_enabled()) {
kvm_s390_set_max_pagesize(pagesize, errp);
}
}
void s390_cmma_reset(void)
{
if (kvm_enabled()) {
kvm_s390_cmma_reset();
}
}
int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
int vq, bool assign)
{
if (kvm_enabled()) {
return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
} else {
return 0;
}
}
void s390_crypto_reset(void)
{
if (kvm_enabled()) {
kvm_s390_crypto_reset();
}
}
void s390_enable_css_support(S390CPU *cpu)
{
if (kvm_enabled()) {
kvm_s390_enable_css_support(cpu);
}
}
void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
{
if (kvm_enabled()) {
kvm_s390_set_diag318(cs, arg.host_ulong);
}
}
s390_cpu_init_sysemu(obj);
#endif
}
static gchar *s390_gdb_arch_name(CPUState *cs)
{
@ -476,17 +261,6 @@ static void s390_cpu_reset_full(DeviceState *dev)
return s390_cpu_reset(s, S390_CPU_RESET_CLEAR);
}
#ifndef CONFIG_USER_ONLY
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps s390_sysemu_ops = {
.get_phys_page_debug = s390_cpu_get_phys_page_debug,
.get_crash_info = s390_cpu_get_crash_info,
.write_elf64_note = s390_cpu_write_elf64_note,
.legacy_vmsd = &vmstate_s390_cpu,
};
#endif
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
@ -515,9 +289,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
dc->user_creatable = true;
device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset);
#if !defined(CONFIG_USER_ONLY)
scc->load_normal = s390_cpu_load_normal;
#endif
scc->reset = s390_cpu_reset;
cc->class_by_name = s390_cpu_class_by_name,
cc->has_work = s390_cpu_has_work;
@ -526,7 +298,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_read_register = s390_cpu_gdb_read_register;
cc->gdb_write_register = s390_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &s390_sysemu_ops;
s390_cpu_class_init_sysemu(cc);
#endif
cc->disas_set_info = s390_cpu_disas_set_info;
cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
@ -546,7 +318,11 @@ static const TypeInfo s390_cpu_type_info = {
.instance_size = sizeof(S390CPU),
.instance_align = __alignof__(S390CPU),
.instance_init = s390_cpu_initfn,
#ifndef CONFIG_USER_ONLY
.instance_finalize = s390_cpu_finalize,
#endif /* !CONFIG_USER_ONLY */
.abstract = true,
.class_size = sizeof(S390CPUClass),
.class_init = s390_cpu_class_init,

View file

@ -109,6 +109,11 @@ DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-
DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility")
DEF_FEAT(NNPA, "nnpa", STFL, 165, "NNPA facility")
DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH2, "vxpdeh2", STFL, 192, "Vector-Packed-Decimal-Enhancement facility 2")
DEF_FEAT(BEAR_ENH, "beareh", STFL, 193, "BEAR-enhancement facility")
DEF_FEAT(RDP, "rdp", STFL, 194, "Reset-DAT-protection facility")
DEF_FEAT(PAI, "pai", STFL, 196, "Processor-Activity-Instrumentation facility")
/* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")

View file

@ -12,24 +12,17 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "kvm_s390x.h"
#include "s390x-internal.h"
#include "kvm/kvm_s390x.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/qemu-print.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qmp/qdict.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/arch_init.h"
#include "sysemu/sysemu.h"
#include "hw/pci/pci.h"
#endif
#include "qapi/qapi-commands-machine-target.h"
#include "hw/s390x/pv.h"
#define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \
@ -88,6 +81,8 @@ static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x3907, 14, 1, 47, 0x08000000U, "z14ZR1", "IBM z14 Model ZR1 GA1"),
CPUDEF_INIT(0x8561, 15, 1, 47, 0x08000000U, "gen15a", "IBM z15 T01 GA1"),
CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM z15 T02 GA1"),
CPUDEF_INIT(0x3931, 16, 1, 47, 0x08000000U, "gen16a", "IBM 3931 GA1"),
CPUDEF_INIT(0x3932, 16, 1, 47, 0x08000000U, "gen16b", "IBM 3932 GA1"),
};
#define QEMU_MAX_CPU_TYPE 0x3906
@ -414,381 +409,6 @@ void s390_cpu_list(void)
}
}
static S390CPUModel *get_max_cpu_model(Error **errp);
#ifndef CONFIG_USER_ONLY
static void list_add_feat(const char *name, void *opaque);
static void check_unavailable_features(const S390CPUModel *max_model,
const S390CPUModel *model,
strList **unavailable)
{
S390FeatBitmap missing;
/* check general model compatibility */
if (max_model->def->gen < model->def->gen ||
(max_model->def->gen == model->def->gen &&
max_model->def->ec_ga < model->def->ec_ga)) {
list_add_feat("type", unavailable);
}
/* detect missing features if any to properly report them */
bitmap_andnot(missing, model->features, max_model->features,
S390_FEAT_MAX);
if (!bitmap_empty(missing, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(missing, unavailable, list_add_feat);
}
}
struct CpuDefinitionInfoListData {
CpuDefinitionInfoList *list;
S390CPUModel *model;
};
static void create_cpu_model_list(ObjectClass *klass, void *opaque)
{
struct CpuDefinitionInfoListData *cpu_list_data = opaque;
CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
CpuDefinitionInfo *info;
char *name = g_strdup(object_class_get_name(klass));
S390CPUClass *scc = S390_CPU_CLASS(klass);
/* strip off the -s390x-cpu */
g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
info = g_new0(CpuDefinitionInfo, 1);
info->name = name;
info->has_migration_safe = true;
info->migration_safe = scc->is_migration_safe;
info->q_static = scc->is_static;
info->q_typename = g_strdup(object_class_get_name(klass));
/* check for unavailable features */
if (cpu_list_data->model) {
Object *obj;
S390CPU *sc;
obj = object_new_with_class(klass);
sc = S390_CPU(obj);
if (sc->model) {
info->has_unavailable_features = true;
check_unavailable_features(cpu_list_data->model, sc->model,
&info->unavailable_features);
}
object_unref(obj);
}
QAPI_LIST_PREPEND(*cpu_list, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
struct CpuDefinitionInfoListData list_data = {
.list = NULL,
};
list_data.model = get_max_cpu_model(NULL);
object_class_foreach(create_cpu_model_list, TYPE_S390_CPU, false,
&list_data);
return list_data.list;
}
static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
Error **errp)
{
Error *err = NULL;
const QDict *qdict = NULL;
const QDictEntry *e;
Visitor *visitor;
ObjectClass *oc;
S390CPU *cpu;
Object *obj;
if (info->props) {
qdict = qobject_to(QDict, info->props);
if (!qdict) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
return;
}
}
oc = cpu_class_by_name(TYPE_S390_CPU, info->name);
if (!oc) {
error_setg(errp, "The CPU definition \'%s\' is unknown.", info->name);
return;
}
if (S390_CPU_CLASS(oc)->kvm_required && !kvm_enabled()) {
error_setg(errp, "The CPU definition '%s' requires KVM", info->name);
return;
}
obj = object_new_with_class(oc);
cpu = S390_CPU(obj);
if (!cpu->model) {
error_setg(errp, "Details about the host CPU model are not available, "
"it cannot be used.");
object_unref(obj);
return;
}
if (qdict) {
visitor = qobject_input_visitor_new(info->props);
if (!visit_start_struct(visitor, NULL, NULL, 0, errp)) {
visit_free(visitor);
object_unref(obj);
return;
}
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
if (!object_property_set(obj, e->key, visitor, &err)) {
break;
}
}
if (!err) {
visit_check_struct(visitor, &err);
}
visit_end_struct(visitor, NULL);
visit_free(visitor);
if (err) {
error_propagate(errp, err);
object_unref(obj);
return;
}
}
/* copy the model and throw the cpu away */
memcpy(model, cpu->model, sizeof(*model));
object_unref(obj);
}
static void qdict_add_disabled_feat(const char *name, void *opaque)
{
qdict_put_bool(opaque, name, false);
}
static void qdict_add_enabled_feat(const char *name, void *opaque)
{
qdict_put_bool(opaque, name, true);
}
/* convert S390CPUDef into a static CpuModelInfo */
static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
bool delta_changes)
{
QDict *qdict = qdict_new();
S390FeatBitmap bitmap;
/* always fallback to the static base model */
info->name = g_strdup_printf("%s-base", model->def->name);
if (delta_changes) {
/* features deleted from the base feature set */
bitmap_andnot(bitmap, model->def->base_feat, model->features,
S390_FEAT_MAX);
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
}
/* features added to the base feature set */
bitmap_andnot(bitmap, model->features, model->def->base_feat,
S390_FEAT_MAX);
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
}
} else {
/* expand all features */
s390_feat_bitmap_to_ascii(model->features, qdict,
qdict_add_enabled_feat);
bitmap_complement(bitmap, model->features, S390_FEAT_MAX);
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
}
if (!qdict_size(qdict)) {
qobject_unref(qdict);
} else {
info->props = QOBJECT(qdict);
info->has_props = true;
}
}
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
CpuModelInfo *model,
Error **errp)
{
Error *err = NULL;
CpuModelExpansionInfo *expansion_info = NULL;
S390CPUModel s390_model;
bool delta_changes = false;
/* convert it to our internal representation */
cpu_model_from_info(&s390_model, model, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
if (type == CPU_MODEL_EXPANSION_TYPE_STATIC) {
delta_changes = true;
} else if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
error_setg(errp, "The requested expansion type is not supported.");
return NULL;
}
/* convert it back to a static representation */
expansion_info = g_new0(CpuModelExpansionInfo, 1);
expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
cpu_info_from_model(expansion_info->model, &s390_model, delta_changes);
return expansion_info;
}
static void list_add_feat(const char *name, void *opaque)
{
strList **last = (strList **) opaque;
QAPI_LIST_PREPEND(*last, g_strdup(name));
}
CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
CpuModelInfo *infob,
Error **errp)
{
Error *err = NULL;
CpuModelCompareResult feat_result, gen_result;
CpuModelCompareInfo *compare_info;
S390FeatBitmap missing, added;
S390CPUModel modela, modelb;
/* convert both models to our internal representation */
cpu_model_from_info(&modela, infoa, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
cpu_model_from_info(&modelb, infob, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
compare_info = g_new0(CpuModelCompareInfo, 1);
/* check the cpu generation and ga level */
if (modela.def->gen == modelb.def->gen) {
if (modela.def->ec_ga == modelb.def->ec_ga) {
/* ec and corresponding bc are identical */
gen_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
} else if (modela.def->ec_ga < modelb.def->ec_ga) {
gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
} else {
gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
}
} else if (modela.def->gen < modelb.def->gen) {
gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
} else {
gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
}
if (gen_result != CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
/* both models cannot be made identical */
list_add_feat("type", &compare_info->responsible_properties);
}
/* check the feature set */
if (bitmap_equal(modela.features, modelb.features, S390_FEAT_MAX)) {
feat_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
} else {
bitmap_andnot(missing, modela.features, modelb.features, S390_FEAT_MAX);
s390_feat_bitmap_to_ascii(missing,
&compare_info->responsible_properties,
list_add_feat);
bitmap_andnot(added, modelb.features, modela.features, S390_FEAT_MAX);
s390_feat_bitmap_to_ascii(added, &compare_info->responsible_properties,
list_add_feat);
if (bitmap_empty(missing, S390_FEAT_MAX)) {
feat_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
} else if (bitmap_empty(added, S390_FEAT_MAX)) {
feat_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
} else {
feat_result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
}
}
/* combine the results */
if (gen_result == feat_result) {
compare_info->result = gen_result;
} else if (feat_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
compare_info->result = gen_result;
} else if (gen_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
compare_info->result = feat_result;
} else {
compare_info->result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
}
return compare_info;
}
CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *infoa,
CpuModelInfo *infob,
Error **errp)
{
Error *err = NULL;
CpuModelBaselineInfo *baseline_info;
S390CPUModel modela, modelb, model;
uint16_t cpu_type;
uint8_t max_gen_ga;
uint8_t max_gen;
/* convert both models to our internal representation */
cpu_model_from_info(&modela, infoa, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
cpu_model_from_info(&modelb, infob, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
/* features both models support */
bitmap_and(model.features, modela.features, modelb.features, S390_FEAT_MAX);
/* detect the maximum model not regarding features */
if (modela.def->gen == modelb.def->gen) {
if (modela.def->type == modelb.def->type) {
cpu_type = modela.def->type;
} else {
cpu_type = 0;
}
max_gen = modela.def->gen;
max_gen_ga = MIN(modela.def->ec_ga, modelb.def->ec_ga);
} else if (modela.def->gen > modelb.def->gen) {
cpu_type = modelb.def->type;
max_gen = modelb.def->gen;
max_gen_ga = modelb.def->ec_ga;
} else {
cpu_type = modela.def->type;
max_gen = modela.def->gen;
max_gen_ga = modela.def->ec_ga;
}
model.def = s390_find_cpu_def(cpu_type, max_gen, max_gen_ga,
model.features);
/* models without early base features (esan3) are bad */
if (!model.def) {
error_setg(errp, "No compatible CPU model could be created as"
" important base features are disabled");
return NULL;
}
/* strip off features not part of the max model */
bitmap_and(model.features, model.features, model.def->full_feat,
S390_FEAT_MAX);
baseline_info = g_new0(CpuModelBaselineInfo, 1);
baseline_info->model = g_malloc0(sizeof(*baseline_info->model));
cpu_info_from_model(baseline_info->model, &model, true);
return baseline_info;
}
#endif
static void check_consistency(const S390CPUModel *model)
{
static int dep[][2] = {
@ -812,6 +432,8 @@ static void check_consistency(const S390CPUModel *model)
{ S390_FEAT_MSA_EXT_9, S390_FEAT_MSA_EXT_4 },
{ S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING },
{ S390_FEAT_VECTOR_PACKED_DECIMAL, S390_FEAT_VECTOR },
{ S390_FEAT_VECTOR_PACKED_DECIMAL_ENH, S390_FEAT_VECTOR_PACKED_DECIMAL },
{ S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2, S390_FEAT_VECTOR_PACKED_DECIMAL_ENH },
{ S390_FEAT_VECTOR_ENH, S390_FEAT_VECTOR },
{ S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 },
{ S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, S390_FEAT_ESOP },
@ -843,6 +465,8 @@ static void check_consistency(const S390CPUModel *model)
{ S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH },
{ S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP },
{ S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB },
{ S390_FEAT_NNPA, S390_FEAT_VECTOR },
{ S390_FEAT_RDP, S390_FEAT_LOCAL_TLB_CLEARING },
};
int i;
@ -900,7 +524,7 @@ static void check_compatibility(const S390CPUModel *max_model,
"available in the configuration: ");
}
static S390CPUModel *get_max_cpu_model(Error **errp)
S390CPUModel *get_max_cpu_model(Error **errp)
{
Error *err = NULL;
static S390CPUModel max_model;
@ -925,39 +549,6 @@ static S390CPUModel *get_max_cpu_model(Error **errp)
return &max_model;
}
static inline void apply_cpu_model(const S390CPUModel *model, Error **errp)
{
#ifndef CONFIG_USER_ONLY
Error *err = NULL;
static S390CPUModel applied_model;
static bool applied;
/*
* We have the same model for all VCPUs. KVM can only be configured before
* any VCPUs are defined in KVM.
*/
if (applied) {
if (model && memcmp(&applied_model, model, sizeof(S390CPUModel))) {
error_setg(errp, "Mixed CPU models are not supported on s390x.");
}
return;
}
if (kvm_enabled()) {
kvm_s390_apply_cpu_model(model, &err);
if (err) {
error_propagate(errp, err);
return;
}
}
applied = true;
if (model) {
applied_model = *model;
}
#endif
}
void s390_realize_cpu_model(CPUState *cs, Error **errp)
{
Error *err = NULL;

View file

@ -0,0 +1,426 @@
/*
* CPU models for s390x - System Emulation-only
*
* Copyright 2016 IBM Corp.
*
* Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "s390x-internal.h"
#include "kvm/kvm_s390x.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qapi-commands-machine-target.h"
static void list_add_feat(const char *name, void *opaque);
static void check_unavailable_features(const S390CPUModel *max_model,
const S390CPUModel *model,
strList **unavailable)
{
S390FeatBitmap missing;
/* check general model compatibility */
if (max_model->def->gen < model->def->gen ||
(max_model->def->gen == model->def->gen &&
max_model->def->ec_ga < model->def->ec_ga)) {
list_add_feat("type", unavailable);
}
/* detect missing features if any to properly report them */
bitmap_andnot(missing, model->features, max_model->features,
S390_FEAT_MAX);
if (!bitmap_empty(missing, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(missing, unavailable, list_add_feat);
}
}
struct CpuDefinitionInfoListData {
CpuDefinitionInfoList *list;
S390CPUModel *model;
};
static void create_cpu_model_list(ObjectClass *klass, void *opaque)
{
struct CpuDefinitionInfoListData *cpu_list_data = opaque;
CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
CpuDefinitionInfo *info;
char *name = g_strdup(object_class_get_name(klass));
S390CPUClass *scc = S390_CPU_CLASS(klass);
/* strip off the -s390x-cpu */
g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
info = g_new0(CpuDefinitionInfo, 1);
info->name = name;
info->has_migration_safe = true;
info->migration_safe = scc->is_migration_safe;
info->q_static = scc->is_static;
info->q_typename = g_strdup(object_class_get_name(klass));
/* check for unavailable features */
if (cpu_list_data->model) {
Object *obj;
S390CPU *sc;
obj = object_new_with_class(klass);
sc = S390_CPU(obj);
if (sc->model) {
info->has_unavailable_features = true;
check_unavailable_features(cpu_list_data->model, sc->model,
&info->unavailable_features);
}
object_unref(obj);
}
QAPI_LIST_PREPEND(*cpu_list, info);
}
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
struct CpuDefinitionInfoListData list_data = {
.list = NULL,
};
list_data.model = get_max_cpu_model(NULL);
object_class_foreach(create_cpu_model_list, TYPE_S390_CPU, false,
&list_data);
return list_data.list;
}
static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
Error **errp)
{
Error *err = NULL;
const QDict *qdict = NULL;
const QDictEntry *e;
Visitor *visitor;
ObjectClass *oc;
S390CPU *cpu;
Object *obj;
if (info->props) {
qdict = qobject_to(QDict, info->props);
if (!qdict) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
return;
}
}
oc = cpu_class_by_name(TYPE_S390_CPU, info->name);
if (!oc) {
error_setg(errp, "The CPU definition \'%s\' is unknown.", info->name);
return;
}
if (S390_CPU_CLASS(oc)->kvm_required && !kvm_enabled()) {
error_setg(errp, "The CPU definition '%s' requires KVM", info->name);
return;
}
obj = object_new_with_class(oc);
cpu = S390_CPU(obj);
if (!cpu->model) {
error_setg(errp, "Details about the host CPU model are not available, "
"it cannot be used.");
object_unref(obj);
return;
}
if (qdict) {
visitor = qobject_input_visitor_new(info->props);
if (!visit_start_struct(visitor, NULL, NULL, 0, errp)) {
visit_free(visitor);
object_unref(obj);
return;
}
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
if (!object_property_set(obj, e->key, visitor, &err)) {
break;
}
}
if (!err) {
visit_check_struct(visitor, &err);
}
visit_end_struct(visitor, NULL);
visit_free(visitor);
if (err) {
error_propagate(errp, err);
object_unref(obj);
return;
}
}
/* copy the model and throw the cpu away */
memcpy(model, cpu->model, sizeof(*model));
object_unref(obj);
}
static void qdict_add_disabled_feat(const char *name, void *opaque)
{
qdict_put_bool(opaque, name, false);
}
static void qdict_add_enabled_feat(const char *name, void *opaque)
{
qdict_put_bool(opaque, name, true);
}
/* convert S390CPUDef into a static CpuModelInfo */
static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
bool delta_changes)
{
QDict *qdict = qdict_new();
S390FeatBitmap bitmap;
/* always fallback to the static base model */
info->name = g_strdup_printf("%s-base", model->def->name);
if (delta_changes) {
/* features deleted from the base feature set */
bitmap_andnot(bitmap, model->def->base_feat, model->features,
S390_FEAT_MAX);
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
}
/* features added to the base feature set */
bitmap_andnot(bitmap, model->features, model->def->base_feat,
S390_FEAT_MAX);
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
}
} else {
/* expand all features */
s390_feat_bitmap_to_ascii(model->features, qdict,
qdict_add_enabled_feat);
bitmap_complement(bitmap, model->features, S390_FEAT_MAX);
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
}
if (!qdict_size(qdict)) {
qobject_unref(qdict);
} else {
info->props = QOBJECT(qdict);
info->has_props = true;
}
}
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
CpuModelInfo *model,
Error **errp)
{
Error *err = NULL;
CpuModelExpansionInfo *expansion_info = NULL;
S390CPUModel s390_model;
bool delta_changes = false;
/* convert it to our internal representation */
cpu_model_from_info(&s390_model, model, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
if (type == CPU_MODEL_EXPANSION_TYPE_STATIC) {
delta_changes = true;
} else if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
error_setg(errp, "The requested expansion type is not supported.");
return NULL;
}
/* convert it back to a static representation */
expansion_info = g_new0(CpuModelExpansionInfo, 1);
expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
cpu_info_from_model(expansion_info->model, &s390_model, delta_changes);
return expansion_info;
}
static void list_add_feat(const char *name, void *opaque)
{
strList **last = (strList **) opaque;
QAPI_LIST_PREPEND(*last, g_strdup(name));
}
CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
CpuModelInfo *infob,
Error **errp)
{
Error *err = NULL;
CpuModelCompareResult feat_result, gen_result;
CpuModelCompareInfo *compare_info;
S390FeatBitmap missing, added;
S390CPUModel modela, modelb;
/* convert both models to our internal representation */
cpu_model_from_info(&modela, infoa, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
cpu_model_from_info(&modelb, infob, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
compare_info = g_new0(CpuModelCompareInfo, 1);
/* check the cpu generation and ga level */
if (modela.def->gen == modelb.def->gen) {
if (modela.def->ec_ga == modelb.def->ec_ga) {
/* ec and corresponding bc are identical */
gen_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
} else if (modela.def->ec_ga < modelb.def->ec_ga) {
gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
} else {
gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
}
} else if (modela.def->gen < modelb.def->gen) {
gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
} else {
gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
}
if (gen_result != CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
/* both models cannot be made identical */
list_add_feat("type", &compare_info->responsible_properties);
}
/* check the feature set */
if (bitmap_equal(modela.features, modelb.features, S390_FEAT_MAX)) {
feat_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
} else {
bitmap_andnot(missing, modela.features, modelb.features, S390_FEAT_MAX);
s390_feat_bitmap_to_ascii(missing,
&compare_info->responsible_properties,
list_add_feat);
bitmap_andnot(added, modelb.features, modela.features, S390_FEAT_MAX);
s390_feat_bitmap_to_ascii(added, &compare_info->responsible_properties,
list_add_feat);
if (bitmap_empty(missing, S390_FEAT_MAX)) {
feat_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
} else if (bitmap_empty(added, S390_FEAT_MAX)) {
feat_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
} else {
feat_result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
}
}
/* combine the results */
if (gen_result == feat_result) {
compare_info->result = gen_result;
} else if (feat_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
compare_info->result = gen_result;
} else if (gen_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
compare_info->result = feat_result;
} else {
compare_info->result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
}
return compare_info;
}
CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *infoa,
CpuModelInfo *infob,
Error **errp)
{
Error *err = NULL;
CpuModelBaselineInfo *baseline_info;
S390CPUModel modela, modelb, model;
uint16_t cpu_type;
uint8_t max_gen_ga;
uint8_t max_gen;
/* convert both models to our internal representation */
cpu_model_from_info(&modela, infoa, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
cpu_model_from_info(&modelb, infob, &err);
if (err) {
error_propagate(errp, err);
return NULL;
}
/* features both models support */
bitmap_and(model.features, modela.features, modelb.features, S390_FEAT_MAX);
/* detect the maximum model not regarding features */
if (modela.def->gen == modelb.def->gen) {
if (modela.def->type == modelb.def->type) {
cpu_type = modela.def->type;
} else {
cpu_type = 0;
}
max_gen = modela.def->gen;
max_gen_ga = MIN(modela.def->ec_ga, modelb.def->ec_ga);
} else if (modela.def->gen > modelb.def->gen) {
cpu_type = modelb.def->type;
max_gen = modelb.def->gen;
max_gen_ga = modelb.def->ec_ga;
} else {
cpu_type = modela.def->type;
max_gen = modela.def->gen;
max_gen_ga = modela.def->ec_ga;
}
model.def = s390_find_cpu_def(cpu_type, max_gen, max_gen_ga,
model.features);
/* models without early base features (esan3) are bad */
if (!model.def) {
error_setg(errp, "No compatible CPU model could be created as"
" important base features are disabled");
return NULL;
}
/* strip off features not part of the max model */
bitmap_and(model.features, model.features, model.def->full_feat,
S390_FEAT_MAX);
baseline_info = g_new0(CpuModelBaselineInfo, 1);
baseline_info->model = g_malloc0(sizeof(*baseline_info->model));
cpu_info_from_model(baseline_info->model, &model, true);
return baseline_info;
}
void apply_cpu_model(const S390CPUModel *model, Error **errp)
{
Error *err = NULL;
static S390CPUModel applied_model;
static bool applied;
/*
* We have the same model for all VCPUs. KVM can only be configured before
* any VCPUs are defined in KVM.
*/
if (applied) {
if (model && memcmp(&applied_model, model, sizeof(S390CPUModel))) {
error_setg(errp, "Mixed CPU models are not supported on s390x.");
}
return;
}
if (kvm_enabled()) {
kvm_s390_apply_cpu_model(model, &err);
if (err) {
error_propagate(errp, err);
return;
}
}
applied = true;
if (model) {
applied_model = *model;
}
}

View file

@ -0,0 +1,20 @@
/*
* CPU models for s390x - User-mode
*
* Copyright 2016 IBM Corp.
*
* Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "s390x-internal.h"
#include "qapi/error.h"
void apply_cpu_model(const S390CPUModel *model, Error **errp)
{
}

View file

@ -14,13 +14,14 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "hw/watchdog/wdt_diag288.h"
#include "sysemu/cpus.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/pv.h"
#include "kvm_s390x.h"
#include "sysemu/kvm.h"
#include "kvm/kvm_s390x.h"
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
@ -168,7 +169,7 @@ out:
return;
}
if (kvm_s390_get_hpage_1m()) {
if (kvm_enabled() && kvm_s390_get_hpage_1m()) {
error_report("Protected VMs can currently not be backed with "
"huge pages");
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;

View file

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu/bitops.h"

View file

@ -424,6 +424,8 @@ static uint16_t base_GEN15_GA1[] = {
S390_FEAT_MISC_INSTRUCTION_EXT3,
};
#define base_GEN16_GA1 EmptyFeat
/* Full features (in order of release)
* Automatically includes corresponding base features.
* Full features are all features this hardware supports even if kvm/QEMU do not
@ -567,6 +569,15 @@ static uint16_t full_GEN15_GA1[] = {
S390_FEAT_UNPACK,
};
static uint16_t full_GEN16_GA1[] = {
S390_FEAT_NNPA,
S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2,
S390_FEAT_BEAR_ENH,
S390_FEAT_RDP,
S390_FEAT_PAI,
};
/* Default features (in order of release)
* Automatically includes corresponding base features.
* Default features are all features this version of QEMU supports for this
@ -652,6 +663,8 @@ static uint16_t default_GEN15_GA1[] = {
S390_FEAT_ETOKEN,
};
#define default_GEN16_GA1 EmptyFeat
/* QEMU (CPU model) features */
static uint16_t qemu_V2_11[] = {
@ -785,6 +798,7 @@ static CpuFeatDefSpec CpuFeatDef[] = {
CPU_FEAT_INITIALIZER(GEN14_GA1),
CPU_FEAT_INITIALIZER(GEN14_GA2),
CPU_FEAT_INITIALIZER(GEN15_GA1),
CPU_FEAT_INITIALIZER(GEN16_GA1),
};
#define FEAT_GROUP_INITIALIZER(_name) \

View file

@ -1,5 +1,5 @@
/*
* S/390 helpers
* S/390 helpers - sysemu only
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf
@ -20,19 +20,15 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "exec/gdbstub.h"
#include "qemu/timer.h"
#include "qemu/qemu-print.h"
#include "hw/s390x/ioinst.h"
#include "hw/s390x/pv.h"
#include "sysemu/hw_accel.h"
#include "sysemu/runstate.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/tcg.h"
#endif
#ifndef CONFIG_USER_ONLY
void s390x_tod_timer(void *opaque)
{
cpu_inject_clock_comparator((S390CPU *) opaque);
@ -285,157 +281,3 @@ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
cpu_physical_memory_unmap(sa, len, 1, len);
return 0;
}
#else
/* For user-only, tcg is always enabled. */
#define tcg_enabled() true
#endif /* CONFIG_USER_ONLY */
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
#ifndef CONFIG_USER_ONLY
uint64_t old_mask = env->psw.mask;
#endif
env->psw.addr = addr;
env->psw.mask = mask;
/* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
if (!tcg_enabled()) {
return;
}
env->cc_op = (mask >> 44) & 3;
#ifndef CONFIG_USER_ONLY
if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(env_cpu(env));
}
if (mask & PSW_MASK_WAIT) {
s390_handle_wait(env_archcpu(env));
}
#endif
}
uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
{
uint64_t r = env->psw.mask;
if (tcg_enabled()) {
uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
env->cc_dst, env->cc_vr);
assert(cc <= 3);
r &= ~PSW_MASK_CC;
r |= cc << 44;
}
return r;
}
void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
int i;
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64,
s390_cpu_get_psw_mask(env), env->psw.addr);
if (!tcg_enabled()) {
qemu_fprintf(f, "\n");
} else if (env->cc_op > 3) {
qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op));
} else {
qemu_fprintf(f, " cc %02x\n", env->cc_op);
}
for (i = 0; i < 16; i++) {
qemu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
if ((i % 4) == 3) {
qemu_fprintf(f, "\n");
} else {
qemu_fprintf(f, " ");
}
}
if (flags & CPU_DUMP_FPU) {
if (s390_has_feat(S390_FEAT_VECTOR)) {
for (i = 0; i < 32; i++) {
qemu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64 "%c",
i, env->vregs[i][0], env->vregs[i][1],
i % 2 ? '\n' : ' ');
}
} else {
for (i = 0; i < 16; i++) {
qemu_fprintf(f, "F%02d=%016" PRIx64 "%c",
i, *get_freg(env, i),
(i % 4) == 3 ? '\n' : ' ');
}
}
}
#ifndef CONFIG_USER_ONLY
for (i = 0; i < 16; i++) {
qemu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
if ((i % 4) == 3) {
qemu_fprintf(f, "\n");
} else {
qemu_fprintf(f, " ");
}
}
#endif
#ifdef DEBUG_INLINE_BRANCHES
for (i = 0; i < CC_OP_MAX; i++) {
qemu_fprintf(f, " %15s = %10ld\t%10ld\n", cc_name(i),
inline_branch_miss[i], inline_branch_hit[i]);
}
#endif
qemu_fprintf(f, "\n");
}
const char *cc_name(enum cc_op cc_op)
{
static const char * const cc_names[] = {
[CC_OP_CONST0] = "CC_OP_CONST0",
[CC_OP_CONST1] = "CC_OP_CONST1",
[CC_OP_CONST2] = "CC_OP_CONST2",
[CC_OP_CONST3] = "CC_OP_CONST3",
[CC_OP_DYNAMIC] = "CC_OP_DYNAMIC",
[CC_OP_STATIC] = "CC_OP_STATIC",
[CC_OP_NZ] = "CC_OP_NZ",
[CC_OP_ADDU] = "CC_OP_ADDU",
[CC_OP_SUBU] = "CC_OP_SUBU",
[CC_OP_LTGT_32] = "CC_OP_LTGT_32",
[CC_OP_LTGT_64] = "CC_OP_LTGT_64",
[CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
[CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
[CC_OP_LTGT0_32] = "CC_OP_LTGT0_32",
[CC_OP_LTGT0_64] = "CC_OP_LTGT0_64",
[CC_OP_ADD_64] = "CC_OP_ADD_64",
[CC_OP_SUB_64] = "CC_OP_SUB_64",
[CC_OP_ABS_64] = "CC_OP_ABS_64",
[CC_OP_NABS_64] = "CC_OP_NABS_64",
[CC_OP_ADD_32] = "CC_OP_ADD_32",
[CC_OP_SUB_32] = "CC_OP_SUB_32",
[CC_OP_ABS_32] = "CC_OP_ABS_32",
[CC_OP_NABS_32] = "CC_OP_NABS_32",
[CC_OP_COMP_32] = "CC_OP_COMP_32",
[CC_OP_COMP_64] = "CC_OP_COMP_64",
[CC_OP_TM_32] = "CC_OP_TM_32",
[CC_OP_TM_64] = "CC_OP_TM_64",
[CC_OP_NZ_F32] = "CC_OP_NZ_F32",
[CC_OP_NZ_F64] = "CC_OP_NZ_F64",
[CC_OP_NZ_F128] = "CC_OP_NZ_F128",
[CC_OP_ICM] = "CC_OP_ICM",
[CC_OP_SLA_32] = "CC_OP_SLA_32",
[CC_OP_SLA_64] = "CC_OP_SLA_64",
[CC_OP_FLOGR] = "CC_OP_FLOGR",
[CC_OP_LCBB] = "CC_OP_LCBB",
[CC_OP_VC] = "CC_OP_VC",
[CC_OP_MULS_32] = "CC_OP_MULS_32",
[CC_OP_MULS_64] = "CC_OP_MULS_64",
};
return cc_names[cc_op];
}

View file

@ -64,18 +64,18 @@ DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(keb, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(kdb, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_5(kxb, TCG_CALL_NO_WG, i32, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(cfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(cfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(cfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(clgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(clgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_3(cgeb, i64, env, i64, i32)
DEF_HELPER_3(cgdb, i64, env, i64, i32)
DEF_HELPER_4(cgxb, i64, env, i64, i64, i32)
DEF_HELPER_3(cfeb, i64, env, i64, i32)
DEF_HELPER_3(cfdb, i64, env, i64, i32)
DEF_HELPER_4(cfxb, i64, env, i64, i64, i32)
DEF_HELPER_3(clgeb, i64, env, i64, i32)
DEF_HELPER_3(clgdb, i64, env, i64, i32)
DEF_HELPER_4(clgxb, i64, env, i64, i64, i32)
DEF_HELPER_3(clfeb, i64, env, i64, i32)
DEF_HELPER_3(clfdb, i64, env, i64, i32)
DEF_HELPER_4(clfxb, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)

View file

@ -9,13 +9,13 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "kvm_s390x.h"
#include "internal.h"
#include "kvm/kvm_s390x.h"
#include "s390x-internal.h"
#include "exec/exec-all.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "hw/s390x/ioinst.h"
#include "tcg_s390x.h"
#include "tcg/tcg_s390x.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/s390x/s390_flic.h"
#endif

View file

@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "hw/s390x/ioinst.h"
#include "trace.h"
#include "hw/s390x/s390-pci-bus.h"

View file

@ -1,121 +0,0 @@
/*
* QEMU KVM support -- s390x specific function stubs.
*
* Copyright (c) 2009 Ulrich Hecht
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "kvm_s390x.h"
void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code)
{
}
int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
int len, bool is_write)
{
return -ENOSYS;
}
void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
{
}
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
{
return -ENOSYS;
}
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
{
}
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
{
return 0;
}
int kvm_s390_get_hpage_1m(void)
{
return 0;
}
int kvm_s390_get_ri(void)
{
return 0;
}
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
{
return -ENOSYS;
}
int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
{
return -ENOSYS;
}
int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
{
return -ENOSYS;
}
int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
{
return -ENOSYS;
}
void kvm_s390_enable_css_support(S390CPU *cpu)
{
}
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign)
{
return -ENOSYS;
}
void kvm_s390_cmma_reset(void)
{
}
void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
{
}
void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
{
}
void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
{
}
int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
{
return 0;
}
void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
{
}
void kvm_s390_crypto_reset(void)
{
}
void kvm_s390_stop_interrupt(S390CPU *cpu)
{
}
void kvm_s390_restart_interrupt(S390CPU *cpu)
{
}
void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
{
}

View file

@ -26,7 +26,7 @@
#include "qemu-common.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "kvm_s390x.h"
#include "sysemu/kvm_int.h"
#include "qemu/cutils.h"

View file

@ -0,0 +1,17 @@
s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
'kvm.c'
))
# Newer kernels on s390 check for an S390_PGSTE program header and
# enable the pgste page table extensions in that case. This makes
# the vm.allocate_pgste sysctl unnecessary. We enable this program
# header if
# - we build on s390x
# - we build the system emulation for s390x (qemu-system-s390x)
# - KVM is enabled
# - the linker supports --s390-pgste
if host_machine.cpu_family() == 's390x' and cc.has_link_argument('-Wl,--s390-pgste')
s390x_softmmu_ss.add(when: 'CONFIG_KVM',
if_true: declare_dependency(link_args: ['-Wl,--s390-pgste']))
endif

View file

@ -0,0 +1,7 @@
# See docs/devel/tracing.txt for syntax documentation.
# kvm.c
kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
kvm_assign_subch_ioeventfd(int fd, uint32_t addr, bool assign, int datamatch) "fd: %d sch: @0x%x assign: %d vq: %d"

1
target/s390x/kvm/trace.h Normal file
View file

@ -0,0 +1 @@
#include "trace/trace-target_s390x_kvm.h"

View file

@ -16,10 +16,10 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "kvm_s390x.h"
#include "s390x-internal.h"
#include "kvm/kvm_s390x.h"
#include "migration/vmstate.h"
#include "tcg_s390x.h"
#include "tcg/tcg_s390x.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"

View file

@ -4,27 +4,10 @@ s390x_ss.add(files(
'cpu_features.c',
'cpu_models.c',
'gdbstub.c',
'helper.c',
'interrupt.c',
'cpu-dump.c',
))
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
'cc_helper.c',
'crypto_helper.c',
'excp_helper.c',
'fpu_helper.c',
'int_helper.c',
'mem_helper.c',
'misc_helper.c',
'translate.c',
'vec_fpu_helper.c',
'vec_helper.c',
'vec_int_helper.c',
'vec_string_helper.c',
), if_false: files('tcg-stub.c'))
s390x_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
gen_features = executable('gen-features', 'gen-features.c', native: true,
build_by_default: false)
@ -37,26 +20,25 @@ s390x_ss.add(gen_features_h)
s390x_softmmu_ss = ss.source_set()
s390x_softmmu_ss.add(files(
'helper.c',
'arch_dump.c',
'diag.c',
'ioinst.c',
'machine.c',
'mmu_helper.c',
'sigp.c',
'cpu-sysemu.c',
'cpu_models_sysemu.c',
))
# Newer kernels on s390 check for an S390_PGSTE program header and
# enable the pgste page table extensions in that case. This makes
# the vm.allocate_pgste sysctl unnecessary. We enable this program
# header if
# - we build on s390x
# - we build the system emulation for s390x (qemu-system-s390x)
# - KVM is enabled
# - the linker supports --s390-pgste
if host_machine.cpu_family() == 's390x' and cc.has_link_argument('-Wl,--s390-pgste')
s390x_softmmu_ss.add(when: 'CONFIG_KVM',
if_true: declare_dependency(link_args: ['-Wl,--s390-pgste']))
endif
s390x_user_ss = ss.source_set()
s390x_user_ss.add(files(
'cpu_models_user.c',
))
subdir('tcg')
subdir('kvm')
target_arch += {'s390x': s390x_ss}
target_softmmu_arch += {'s390x': s390x_softmmu_ss}
target_user_arch += {'s390x': s390x_user_ss}

View file

@ -19,8 +19,8 @@
#include "qemu/error-report.h"
#include "exec/address-spaces.h"
#include "cpu.h"
#include "internal.h"
#include "kvm_s390x.h"
#include "s390x-internal.h"
#include "kvm/kvm_s390x.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "exec/exec-all.h"

View file

@ -240,6 +240,12 @@ uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
#ifndef CONFIG_USER_ONLY
unsigned int s390_cpu_halt(S390CPU *cpu);
void s390_cpu_unhalt(S390CPU *cpu);
void s390_cpu_init_sysemu(Object *obj);
bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp);
void s390_cpu_finalize(Object *obj);
void s390_cpu_class_init_sysemu(CPUClass *cc);
void s390_cpu_machine_reset_cb(void *opaque);
#else
static inline unsigned int s390_cpu_halt(S390CPU *cpu)
{
@ -255,6 +261,8 @@ static inline void s390_cpu_unhalt(S390CPU *cpu)
/* cpu_models.c */
void s390_cpu_model_class_register_props(ObjectClass *oc);
void s390_realize_cpu_model(CPUState *cs, Error **errp);
S390CPUModel *get_max_cpu_model(Error **errp);
void apply_cpu_model(const S390CPUModel *model, Error **errp);
ObjectClass *s390_cpu_class_by_name(const char *name);

View file

@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "sysemu/hw_accel.h"
#include "sysemu/runstate.h"
#include "exec/address-spaces.h"

View file

@ -1,30 +0,0 @@
/*
* QEMU TCG support -- s390x specific function stubs.
*
* Copyright (C) 2018 Red Hat Inc
*
* Authors:
* David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "tcg_s390x.h"
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
{
}
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
uint32_t code, uintptr_t ra)
{
g_assert_not_reached();
}
void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
uintptr_t ra)
{
g_assert_not_reached();
}

View file

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"

View file

@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "internal.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"

View file

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "exec/helper-proto.h"
#include "qemu/timer.h"
#include "exec/exec-all.h"

View file

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
@ -168,6 +168,34 @@ uint32_t set_cc_nz_f128(float128 v)
}
}
/* condition codes for FP to integer conversion ops */
static uint32_t set_cc_conv_f32(float32 v, float_status *stat)
{
if (stat->float_exception_flags & float_flag_invalid) {
return 3;
} else {
return set_cc_nz_f32(v);
}
}
static uint32_t set_cc_conv_f64(float64 v, float_status *stat)
{
if (stat->float_exception_flags & float_flag_invalid) {
return 3;
} else {
return set_cc_nz_f64(v);
}
}
static uint32_t set_cc_conv_f128(float128 v, float_status *stat)
{
if (stat->float_exception_flags & float_flag_invalid) {
return 3;
} else {
return set_cc_nz_f128(v);
}
}
static inline uint8_t round_from_m34(uint32_t m34)
{
return extract32(m34, 0, 4);
@ -506,9 +534,11 @@ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int64_t ret = float32_to_int64(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float32_is_any_nan(v2)) {
return INT64_MIN;
}
@ -520,9 +550,11 @@ uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int64_t ret = float64_to_int64(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float64_is_any_nan(v2)) {
return INT64_MIN;
}
@ -535,9 +567,11 @@ uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 v2 = make_float128(h, l);
int64_t ret = float128_to_int64(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float128_is_any_nan(v2)) {
return INT64_MIN;
}
@ -549,9 +583,11 @@ uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int32_t ret = float32_to_int32(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float32_is_any_nan(v2)) {
return INT32_MIN;
}
@ -563,9 +599,11 @@ uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int32_t ret = float64_to_int32(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float64_is_any_nan(v2)) {
return INT32_MIN;
}
@ -578,9 +616,11 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 v2 = make_float128(h, l);
int32_t ret = float128_to_int32(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float128_is_any_nan(v2)) {
return INT32_MIN;
}
@ -592,8 +632,11 @@ uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret = float32_to_uint64(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float32_is_any_nan(v2)) {
return 0;
}
@ -605,9 +648,11 @@ uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float64_is_any_nan(v2)) {
return 0;
}
@ -618,11 +663,14 @@ uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status);
float128 v2 = make_float128(h, l);
uint64_t ret = float128_to_uint64(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float128_is_any_nan(make_float128(h, l))) {
env->cc_op = cc;
if (float128_is_any_nan(v2)) {
return 0;
}
return ret;
@ -633,9 +681,11 @@ uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float32_is_any_nan(v2)) {
return 0;
}
@ -647,9 +697,11 @@ uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
env->cc_op = cc;
if (float64_is_any_nan(v2)) {
return 0;
}
@ -660,11 +712,14 @@ uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status);
float128 v2 = make_float128(h, l);
uint32_t ret = float128_to_uint32(v2, &env->fpu_status);
uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float128_is_any_nan(make_float128(h, l))) {
env->cc_op = cc;
if (float128_is_any_nan(v2)) {
return 0;
}
return ret;

View file

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"

View file

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"

View file

@ -0,0 +1,14 @@
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
'cc_helper.c',
'crypto_helper.c',
'excp_helper.c',
'fpu_helper.c',
'int_helper.c',
'mem_helper.c',
'misc_helper.c',
'translate.c',
'vec_fpu_helper.c',
'vec_helper.c',
'vec_int_helper.c',
'vec_string_helper.c',
))

View file

@ -22,7 +22,7 @@
#include "qemu/cutils.h"
#include "qemu/main-loop.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "exec/memory.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"

View file

@ -30,7 +30,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
@ -562,21 +562,6 @@ static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
gen_op_update1_cc_i64(s, CC_OP_NZ, val);
}
static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val)
{
gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val);
}
static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val)
{
gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val);
}
static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl)
{
gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl);
}
/* CC value is in env->cc_op */
static void set_cc_static(DisasContext *s)
{
@ -1823,7 +1808,7 @@ static DisasJumpType op_cfeb(DisasContext *s, DisasOps *o)
}
gen_helper_cfeb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f32(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1836,7 +1821,7 @@ static DisasJumpType op_cfdb(DisasContext *s, DisasOps *o)
}
gen_helper_cfdb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f64(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1849,7 +1834,7 @@ static DisasJumpType op_cfxb(DisasContext *s, DisasOps *o)
}
gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f128(s, o->in1, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1862,7 +1847,7 @@ static DisasJumpType op_cgeb(DisasContext *s, DisasOps *o)
}
gen_helper_cgeb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f32(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1875,7 +1860,7 @@ static DisasJumpType op_cgdb(DisasContext *s, DisasOps *o)
}
gen_helper_cgdb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f64(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1888,7 +1873,7 @@ static DisasJumpType op_cgxb(DisasContext *s, DisasOps *o)
}
gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f128(s, o->in1, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1901,7 +1886,7 @@ static DisasJumpType op_clfeb(DisasContext *s, DisasOps *o)
}
gen_helper_clfeb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f32(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1914,7 +1899,7 @@ static DisasJumpType op_clfdb(DisasContext *s, DisasOps *o)
}
gen_helper_clfdb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f64(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1927,7 +1912,7 @@ static DisasJumpType op_clfxb(DisasContext *s, DisasOps *o)
}
gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f128(s, o->in1, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1940,7 +1925,7 @@ static DisasJumpType op_clgeb(DisasContext *s, DisasOps *o)
}
gen_helper_clgeb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f32(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1953,7 +1938,7 @@ static DisasJumpType op_clgdb(DisasContext *s, DisasOps *o)
}
gen_helper_clgdb(o->out, cpu_env, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f64(s, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}
@ -1966,7 +1951,7 @@ static DisasJumpType op_clgxb(DisasContext *s, DisasOps *o)
}
gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m34);
tcg_temp_free_i32(m34);
gen_set_cc_nz_f128(s, o->in1, o->in2);
set_cc_static(s);
return DISAS_NEXT;
}

View file

@ -1783,7 +1783,7 @@ static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
{
TCGv_i64 l1, h1, l2, h2;
if (get_field(s, m4) != ES_64) {
if (get_field(s, m5) != ES_64) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}

View file

@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "vec.h"
#include "tcg_s390x.h"
#include "tcg/tcg-gvec-desc.h"

View file

@ -11,7 +11,7 @@
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "vec.h"
#include "tcg/tcg.h"
#include "tcg/tcg-gvec-desc.h"

View file

@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "internal.h"
#include "s390x-internal.h"
#include "vec.h"
#include "tcg/tcg.h"
#include "tcg/tcg-gvec-desc.h"

View file

@ -10,13 +10,7 @@ ioinst_sch_id(const char *insn, int cssid, int ssid, int schid) "IOINST: %s (%x.
ioinst_chp_id(const char *insn, int cssid, int chpid) "IOINST: %s (%x.%02x)"
ioinst_chsc_cmd(uint16_t cmd, uint16_t len) "IOINST: chsc command 0x%04x, len 0x%04x"
# kvm.c
kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
kvm_assign_subch_ioeventfd(int fd, uint32_t addr, bool assign, int datamatch) "fd: %d sch: @0x%x assign: %d vq: %d"
# cpu.c
# cpu-sysemu.c
cpu_set_state(int cpu_index, uint8_t state) "setting cpu %d state to %" PRIu8
cpu_halt(int cpu_index) "halting cpu %d"
cpu_unhalt(int cpu_index) "unhalting cpu %d"