Files
unicorn/qemu/target/s390x/cpu.c
mio ffeddd7579 use qemu_memalign for all cpu structs
Some structs, specically CPUARMState is 16-bytes aligned.

This causes segment fault because gcc tends to vectorize

the assignment of the struct with infamous movaps tricks.

Without this patch, we fail on manylinux with 2.17 glibc

in release mode in i686.

qemu_memalign will ensure the alignment across platforms.
2024-10-17 13:50:07 +08:00

295 lines
7.4 KiB
C

/*
* QEMU S/390 CPU
*
* 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 "cpu.h"
#include "internal.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "fpu/softfloat-helpers.h"
#include "exec/exec-all.h"
#define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL;
static void s390_cpu_set_pc(CPUState *cs, vaddr value)
{
S390CPU *cpu = S390_CPU(cs);
cpu->env.psw.addr = value;
}
static bool s390_cpu_has_work(CPUState *cs)
{
S390CPU *cpu = S390_CPU(cs);
#if 0
/* STOPPED cpus can never wake up */
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD &&
s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
return false;
}
#endif
if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
return false;
}
return s390_cpu_has_int(cpu);
}
/* S390CPUClass::reset() */
static void s390_cpu_reset(CPUState *dev, cpu_reset_type type)
{
CPUState *s = CPU(dev);
S390CPU *cpu = S390_CPU(s);
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
CPUS390XState *env = &cpu->env;
scc->parent_reset(dev);
cpu->env.sigp_order = 0;
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
switch (type) {
case S390_CPU_RESET_CLEAR:
memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields));
/* fall through */
case S390_CPU_RESET_INITIAL:
/* initial reset does not clear everything! */
memset(&env->start_initial_reset_fields, 0,
offsetof(CPUS390XState, start_normal_reset_fields) -
offsetof(CPUS390XState, start_initial_reset_fields));
/* architectured initial value for Breaking-Event-Address register */
env->gbea = 1;
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
/* tininess for underflow is detected before rounding */
set_float_detect_tininess(float_tininess_before_rounding,
&env->fpu_status);
/* fall through */
case S390_CPU_RESET_NORMAL:
env->psw.mask &= ~PSW_MASK_RI;
memset(&env->start_normal_reset_fields, 0,
offsetof(CPUS390XState, end_reset_fields) -
offsetof(CPUS390XState, start_normal_reset_fields));
env->pfault_token = -1UL;
env->bpbc = false;
break;
default:
g_assert_not_reached();
}
}
static void s390_cpu_realizefn(struct uc_struct *uc, CPUState *dev)
{
CPUState *cs = CPU(dev);
S390CPU *cpu = S390_CPU(dev);
/* the model has to be realized before qemu_init_vcpu() due to kvm */
// s390_realize_cpu_model(cs);
/* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
cs->cpu_index = cpu->env.core_id;
cpu_exec_realizefn(cs);
qemu_init_vcpu(cs);
cpu_reset(cs);
}
static void s390_cpu_initfn(struct uc_struct *uc, CPUState *obj)
{
CPUState *cs = CPU(obj);
S390CPU *cpu = S390_CPU(obj);
cpu_set_cpustate_pointers(cpu);
cs->halted = 1;
cs->exception_index = EXCP_HLT;
// s390_cpu_model_register_props(obj);
// 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);
cpu->env.uc = uc;
}
static unsigned s390_count_running_cpus(void)
{
return 1;
}
unsigned int s390_cpu_halt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
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);
if (cs->halted) {
cs->halted = 0;
cs->exception_index = -1;
}
}
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
{
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 (!(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);
}
cpu->env.cpu_state = cpu_state;
return s390_count_running_cpus();
}
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
{
return 0;
}
void s390_set_max_pagesize(uint64_t pagesize)
{
}
void s390_cmma_reset(void)
{
}
void s390_crypto_reset(void)
{
}
void s390_enable_css_support(S390CPU *cpu)
{
}
static void s390_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
{
S390CPUClass *scc = S390_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(scc);
scc->reset = s390_cpu_reset;
cc->has_work = s390_cpu_has_work;
// cc->do_interrupt = s390_cpu_do_interrupt;
cc->set_pc = s390_cpu_set_pc;
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
cc->tcg_initialize = s390x_translate_init;
cc->tlb_fill_cpu = s390_cpu_tlb_fill;
// s390_cpu_model_class_register_props(oc);
}
S390CPU *cpu_s390_init(struct uc_struct *uc, const char *cpu_model)
{
S390CPU *cpu;
CPUState *cs;
CPUClass *cc;
// int i;
cpu = qemu_memalign(8, sizeof(*cpu));
if (cpu == NULL) {
return NULL;
}
memset((void*)cpu, 0, sizeof(*cpu));
if (uc->cpu_model == INT_MAX) {
uc->cpu_model = UC_CPU_S390X_QEMU; // qemu-s390x-cpu
} else if (uc->cpu_model > UC_CPU_S390X_MAX) {
free(cpu);
return NULL;
}
cs = (CPUState *)cpu;
cc = (CPUClass *)&cpu->cc;
cs->cc = cc;
cs->uc = uc;
uc->cpu = (CPUState *)cpu;
/* init CPUClass */
cpu_class_init(uc, cc);
/* 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);
/* realize CPU */
s390_cpu_realizefn(uc, cs);
// init addresss space
cpu_address_space_init(cs, 0, cs->memory);
//qemu_init_vcpu(cs);
return cpu;
}