aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/s390x/arch_dump.c66
-rw-r--r--target/s390x/kvm.c43
2 files changed, 80 insertions, 29 deletions
diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c
index 4731869..105ae9a 100644
--- a/target/s390x/arch_dump.c
+++ b/target/s390x/arch_dump.c
@@ -59,8 +59,7 @@ typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
typedef struct noteStruct {
Elf64_Nhdr hdr;
- char name[5];
- char pad3[3];
+ char name[8];
union {
S390xElfPrstatus prstatus;
S390xElfFpregset fpregset;
@@ -74,7 +73,7 @@ typedef struct noteStruct {
} contents;
} QEMU_PACKED Note;
-static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id)
{
int i;
S390xUserRegs *regs;
@@ -88,9 +87,10 @@ static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu)
regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]);
regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]);
}
+ note->contents.prstatus.pid = id;
}
-static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id)
{
int i;
CPUS390XState *cs = &cpu->env;
@@ -102,7 +102,7 @@ static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu)
}
}
-static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu, int id)
{
int i;
@@ -112,7 +112,7 @@ static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu)
}
}
-static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
{
int i;
S390xElfVregsHi *temp_vregshi;
@@ -126,25 +126,25 @@ static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu)
}
}
-static void s390x_write_elf64_timer(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id)
{
note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm));
}
-static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id)
{
note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP);
note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc));
}
-static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id)
{
note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG);
note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr));
}
-static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id)
{
int i;
@@ -155,20 +155,26 @@ static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu)
}
}
-static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu)
+static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id)
{
note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX);
note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa));
}
-static const struct NoteFuncDescStruct {
+typedef struct NoteFuncDescStruct {
int contents_size;
- void (*note_contents_func)(Note *note, S390CPU *cpu);
-} note_func[] = {
+ void (*note_contents_func)(Note *note, S390CPU *cpu, int id);
+} NoteFuncDesc;
+
+static const NoteFuncDesc note_core[] = {
{sizeof(((Note *)0)->contents.prstatus), s390x_write_elf64_prstatus},
- {sizeof(((Note *)0)->contents.prefix), s390x_write_elf64_prefix},
{sizeof(((Note *)0)->contents.fpregset), s390x_write_elf64_fpregset},
+ { 0, NULL}
+};
+
+static const NoteFuncDesc note_linux[] = {
+ {sizeof(((Note *)0)->contents.prefix), s390x_write_elf64_prefix},
{sizeof(((Note *)0)->contents.ctrs), s390x_write_elf64_ctrs},
{sizeof(((Note *)0)->contents.timer), s390x_write_elf64_timer},
{sizeof(((Note *)0)->contents.todcmp), s390x_write_elf64_todcmp},
@@ -178,25 +184,23 @@ static const struct NoteFuncDescStruct {
{ 0, NULL}
};
-typedef struct NoteFuncDescStruct NoteFuncDesc;
-
-
-static int s390x_write_all_elf64_notes(const char *note_name,
+static int s390x_write_elf64_notes(const char *note_name,
WriteCoreDumpFunction f,
S390CPU *cpu, int id,
- void *opaque)
+ void *opaque,
+ const NoteFuncDesc *funcs)
{
Note note;
const NoteFuncDesc *nf;
int note_size;
int ret = -1;
- for (nf = note_func; nf->note_contents_func; nf++) {
+ for (nf = funcs; nf->note_contents_func; nf++) {
memset(&note, 0, sizeof(note));
- note.hdr.n_namesz = cpu_to_be32(sizeof(note.name));
+ note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1);
note.hdr.n_descsz = cpu_to_be32(nf->contents_size);
strncpy(note.name, note_name, sizeof(note.name));
- (*nf->note_contents_func)(&note, cpu);
+ (*nf->note_contents_func)(&note, cpu, id);
note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size;
ret = f(&note, note_size, opaque);
@@ -215,7 +219,13 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque)
{
S390CPU *cpu = S390_CPU(cs);
- return s390x_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque);
+ int r;
+
+ r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core);
+ if (r) {
+ return r;
+ }
+ return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux);
}
int cpu_get_dump_info(ArchDumpInfo *info,
@@ -230,7 +240,7 @@ int cpu_get_dump_info(ArchDumpInfo *info,
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
{
- int name_size = 8; /* "CORE" or "QEMU" rounded */
+ int name_size = 8; /* "LINUX" or "CORE" + pad */
size_t elf_note_size = 0;
int note_head_size;
const NoteFuncDesc *nf;
@@ -240,7 +250,11 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
note_head_size = sizeof(Elf64_Nhdr);
- for (nf = note_func; nf->note_contents_func; nf++) {
+ for (nf = note_core; nf->note_contents_func; nf++) {
+ elf_note_size = elf_note_size + note_head_size + name_size +
+ nf->contents_size;
+ }
+ for (nf = note_linux; nf->note_contents_func; nf++) {
elf_note_size = elf_note_size + note_head_size + name_size +
nf->contents_size;
}
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 2536780..5ec050c 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -1867,6 +1867,40 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset)
qemu_system_guest_panicked(NULL);
}
+/* try to detect pgm check loops */
+static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run)
+{
+ CPUState *cs = CPU(cpu);
+ PSW oldpsw, newpsw;
+
+ cpu_synchronize_state(cs);
+ newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
+ offsetof(LowCore, program_new_psw));
+ newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
+ offsetof(LowCore, program_new_psw) + 8);
+ oldpsw.mask = run->psw_mask;
+ oldpsw.addr = run->psw_addr;
+ /*
+ * Avoid endless loops of operation exceptions, if the pgm new
+ * PSW will cause a new operation exception.
+ * The heuristic checks if the pgm new psw is within 6 bytes before
+ * the faulting psw address (with same DAT, AS settings) and the
+ * new psw is not a wait psw and the fault was not triggered by
+ * problem state. In that case go into crashed state.
+ */
+
+ if (oldpsw.addr - newpsw.addr <= 6 &&
+ !(newpsw.mask & PSW_MASK_WAIT) &&
+ !(oldpsw.mask & PSW_MASK_PSTATE) &&
+ (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
+ (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) {
+ unmanageable_intercept(cpu, "operation exception loop",
+ offsetof(LowCore, program_new_psw));
+ return EXCP_HALTED;
+ }
+ return 0;
+}
+
static int handle_intercept(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
@@ -1914,11 +1948,14 @@ static int handle_intercept(S390CPU *cpu)
r = EXCP_HALTED;
break;
case ICPT_OPEREXC:
- /* currently only instr 0x0000 after enabled via capability */
+ /* check for break points */
r = handle_sw_breakpoint(cpu, run);
if (r == -ENOENT) {
- enter_pgmcheck(cpu, PGM_OPERATION);
- r = 0;
+ /* Then check for potential pgm check loops */
+ r = handle_oper_loop(cpu, run);
+ if (r == 0) {
+ enter_pgmcheck(cpu, PGM_OPERATION);
+ }
}
break;
case ICPT_SOFT_INTERCEPT: