mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
235 lines
6.1 KiB
C
235 lines
6.1 KiB
C
/*
|
|
* zgetdump - Tool for copying and converting System z dumps
|
|
*
|
|
* S390 dump output format
|
|
*
|
|
* Copyright IBM Corp. 2001, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "zgetdump.h"
|
|
|
|
/*
|
|
* File local static data
|
|
*/
|
|
static struct {
|
|
struct df_s390_hdr hdr;
|
|
struct df_s390_em em;
|
|
} l;
|
|
|
|
/*
|
|
* Copy internal register set to 64 bit lowcore
|
|
*/
|
|
static void cpu2lc_64(void *lc_64, struct dfi_cpu *cpu)
|
|
{
|
|
struct dfi_lowcore_64 *lc = lc_64;
|
|
memcpy(lc->gpregs_save_area, &cpu->gprs, sizeof(cpu->gprs));
|
|
memcpy(lc->cregs_save_area, &cpu->ctrs, sizeof(cpu->ctrs));
|
|
memcpy(lc->access_regs_save_area, &cpu->acrs, sizeof(cpu->acrs));
|
|
memcpy(lc->floating_pt_save_area, &cpu->fprs, sizeof(cpu->fprs));
|
|
memcpy(&lc->fpt_creg_save_area, &cpu->fpc, sizeof(cpu->fpc));
|
|
memcpy(lc->st_status_fixed_logout, &cpu->psw, sizeof(cpu->psw));
|
|
memcpy(&lc->prefixreg_save_area, &cpu->prefix, sizeof(cpu->prefix));
|
|
memcpy(lc->timer_save_area, &cpu->timer, sizeof(cpu->timer));
|
|
memcpy(lc->clock_comp_save_area, &cpu->todcmp, sizeof(cpu->todcmp));
|
|
}
|
|
|
|
/*
|
|
* Copy internal register set to 32 bit lowcore
|
|
*/
|
|
static void cpu2lc_32(void *lc_32, struct dfi_cpu *cpu_64)
|
|
{
|
|
struct dfi_lowcore_32 *lc = lc_32;
|
|
struct dfi_cpu_32 cpu;
|
|
|
|
dfi_cpu_64_to_32(&cpu, cpu_64);
|
|
memcpy(lc->gpregs_save_area, &cpu.gprs, sizeof(cpu.gprs));
|
|
memcpy(lc->cregs_save_area, &cpu.ctrs, sizeof(cpu.ctrs));
|
|
memcpy(lc->access_regs_save_area, &cpu.acrs, sizeof(cpu.acrs));
|
|
memcpy(lc->floating_pt_save_area, &cpu.fprs, sizeof(cpu.fprs));
|
|
memcpy(lc->st_status_fixed_logout, &cpu.psw, sizeof(cpu.psw));
|
|
memcpy(&lc->prefixreg_save_area, &cpu.prefix, sizeof(cpu.prefix));
|
|
memcpy(lc->timer_save_area, &cpu.timer, sizeof(cpu.timer));
|
|
memcpy(lc->clock_comp_save_area, &cpu.todcmp, sizeof(cpu.todcmp));
|
|
}
|
|
|
|
/*
|
|
* Convert timeval to s390 TOD clock
|
|
*/
|
|
static void timeval2tod(u64 *tod, struct timeval *xtime)
|
|
{
|
|
u64 us = xtime->tv_sec * 1000000 + xtime->tv_usec;
|
|
*tod = (us << 12);
|
|
*tod += 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
|
|
}
|
|
|
|
/*
|
|
* Setup lowcore array in dump header
|
|
*/
|
|
static void lc_setup(struct df_s390_hdr *dh)
|
|
{
|
|
struct dfi_cpu *cpu;
|
|
unsigned int i = 0;
|
|
|
|
dfi_cpu_iterate(cpu) {
|
|
if (i >= DF_S390_CPU_MAX)
|
|
ERR_EXIT("Too many CPUs in source dump (%i)", i);
|
|
dh->lc_vec[i] = cpu->prefix;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Copy register set to prefix page
|
|
*/
|
|
static void dfo_s390_dump_chunk_lc_fn(struct dfo_chunk *dump_chunk,
|
|
u64 off, void *buf, u64 cnt)
|
|
{
|
|
struct dfi_cpu *cpu = dump_chunk->data;
|
|
char lc[0x2000];
|
|
|
|
dfi_mem_read(cpu->prefix + off, &lc[off], cnt);
|
|
if (dfi_arch() == DFI_ARCH_64)
|
|
cpu2lc_64(lc, cpu);
|
|
else
|
|
cpu2lc_32(lc, cpu);
|
|
memcpy(buf, &lc[off], cnt);
|
|
}
|
|
|
|
/*
|
|
* Copy register set to prefix page
|
|
*/
|
|
static void dfo_s390_dump_chunk_vx_fn(struct dfo_chunk *dump_chunk,
|
|
u64 off, void *buf, u64 cnt)
|
|
{
|
|
char *vx_regs = dump_chunk->data;
|
|
|
|
memcpy(buf, &vx_regs[off], cnt);
|
|
}
|
|
|
|
/*
|
|
* Add register set to dump layout. We copy the register sets to the
|
|
* lowcore pages.
|
|
*/
|
|
static void add_cpu_to_dfo(struct dfi_cpu *cpu)
|
|
{
|
|
struct dfi_lowcore_64 lc;
|
|
void *vx_regs;
|
|
|
|
if (dfi_cpu_content() != DFI_CPU_CONTENT_ALL)
|
|
return;
|
|
if (!dfi_mem_range_valid(cpu->prefix, dfi_lc_size(dfi_arch()))) {
|
|
STDERR("Info: Could not read CPU prefix page: %x\n",
|
|
cpu->prefix);
|
|
return;
|
|
}
|
|
/* Add lowcore to memory */
|
|
dfo_chunk_add(cpu->prefix + DF_S390_HDR_SIZE,
|
|
dfi_lc_size(dfi_arch()), cpu,
|
|
dfo_s390_dump_chunk_lc_fn);
|
|
/* Add VX save area to memory */
|
|
if (dfi_arch() != DFI_ARCH_64)
|
|
return;
|
|
if (!dfi_cpu_content_fac_check(DFI_CPU_CONTENT_FAC_VX))
|
|
return;
|
|
dfi_mem_read(cpu->prefix, &lc, sizeof(lc));
|
|
if (!dfi_cpu_lc_has_vx_sa(&lc))
|
|
return;
|
|
vx_regs = zg_alloc(DFI_VX_SA_SIZE);
|
|
dfi_cpu_vx_copy(vx_regs, cpu);
|
|
dfo_chunk_add(lc.vector_save_area_addr + DF_S390_HDR_SIZE,
|
|
DFI_VX_SA_SIZE, vx_regs, dfo_s390_dump_chunk_vx_fn);
|
|
}
|
|
|
|
/*
|
|
* Add memory chunk to dump layout
|
|
*/
|
|
static void add_mem_chunk_to_dfo(struct dfi_mem_chunk *mem_chunk)
|
|
{
|
|
struct dfi_mem_chunk *mem_chunk_prev = dfi_mem_chunk_prev(mem_chunk);
|
|
|
|
if (mem_chunk_prev && (mem_chunk_prev->end + 1 != mem_chunk->start))
|
|
dfo_chunk_add(mem_chunk_prev->end + 1 + DF_S390_HDR_SIZE,
|
|
mem_chunk->start - mem_chunk_prev->end - 1,
|
|
NULL, dfo_chunk_zero_fn);
|
|
|
|
dfo_chunk_add(mem_chunk->start + DF_S390_HDR_SIZE, mem_chunk->size,
|
|
mem_chunk, dfo_chunk_mem_fn);
|
|
}
|
|
|
|
/*
|
|
* Setup dump chunks
|
|
*/
|
|
static void dump_chunks_init(void)
|
|
{
|
|
struct dfi_mem_chunk *mem_chunk;
|
|
struct dfi_cpu *cpu;
|
|
|
|
dfo_chunk_add(0, DF_S390_HDR_SIZE, &l.hdr, dfo_chunk_buf_fn);
|
|
dfi_mem_chunk_iterate(mem_chunk)
|
|
add_mem_chunk_to_dfo(mem_chunk);
|
|
dfi_cpu_iterate(cpu)
|
|
add_cpu_to_dfo(cpu);
|
|
dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE,
|
|
DF_S390_EM_SIZE,
|
|
&l.em, dfo_chunk_buf_fn);
|
|
}
|
|
|
|
/*
|
|
* Initialize s390 output dump format
|
|
*/
|
|
static void df_s390_dump_init(void)
|
|
{
|
|
struct df_s390_hdr *dh = &l.hdr;
|
|
struct df_s390_em *em = &l.em;
|
|
|
|
dh->magic = DF_S390_MAGIC;
|
|
dh->hdr_size = DF_S390_HDR_SIZE;
|
|
dh->page_size = PAGE_SIZE;
|
|
dh->dump_level = 4;
|
|
if (dfi_cpu_content() == DFI_CPU_CONTENT_NONE)
|
|
dh->version = 4;
|
|
else
|
|
dh->version = 5;
|
|
dh->mem_start = 0;
|
|
dh->mem_size = dh->mem_end = dfi_mem_range();
|
|
dh->num_pages = dh->mem_size / PAGE_SIZE;
|
|
dh->arch = df_s390_from_dfi_arch(dfi_arch());
|
|
if (dfi_attr_build_arch())
|
|
dh->build_arch = df_s390_from_dfi_arch(*dfi_attr_build_arch());
|
|
dh->cpu_cnt = dfi_cpu_cnt();
|
|
if (dfi_attr_real_cpu_cnt())
|
|
dh->real_cpu_cnt = *dfi_attr_real_cpu_cnt();
|
|
if (dfi_attr_cpu_id())
|
|
dh->cpu_id = *dfi_attr_cpu_id();
|
|
if (dfi_attr_mem_size_real())
|
|
dh->mem_size_real = *dfi_attr_mem_size_real();
|
|
if (dfi_attr_time()) {
|
|
timeval2tod(&dh->tod, dfi_attr_time());
|
|
timeval2tod(&em->tod, dfi_attr_time());
|
|
}
|
|
if (dfi_attr_time_end())
|
|
timeval2tod(&em->tod, dfi_attr_time_end());
|
|
lc_setup(dh);
|
|
memcpy(em->str, DF_S390_EM_STR, sizeof(em->str));
|
|
dump_chunks_init();
|
|
}
|
|
|
|
/*
|
|
* S390 DFO operations
|
|
*/
|
|
struct dfo dfo_s390 = {
|
|
.name = "s390",
|
|
.init = df_s390_dump_init,
|
|
};
|