/* * zgetdump - Tool for copying and converting System z dumps * * kdump and kdump_flat input 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 #include "zgetdump.h" #include "zg.h" #include "dfi.h" #include "dfi_mem_chunk.h" struct df_kdump_hdr { char signature[8]; int header_version; struct new_utsname utsname; struct timeval timestamp; unsigned int status; int block_size; int sub_hdr_size; unsigned int bitmap_blocks; unsigned int max_mapnr; unsigned int total_ram_blocks; unsigned int device_blocks; unsigned int written_blocks; unsigned int current_cpu; int nr_cpus; void *tasks[0]; }; struct df_kdump_sub_hdr { unsigned long phys_base; int dump_level; int split; unsigned long start_pfn; unsigned long end_pfn; off_t offset_vmcoreinfo; unsigned long size_vmcoreinfo; }; struct df_kdump_flat_hdr { char signature[16]; u64 type; u64 version; }; struct df_kdump_flat_data_hdr { s64 offs; s64 size; }; /* * File local static data */ static struct { struct df_kdump_hdr hdr; /* kdump (diskdump) dump header */ struct df_kdump_sub_hdr shdr; /* kdump subheader */ } l; #ifdef DEBUG static void print_header(void) { STDERR("diskdump main header\n"); STDERR(" signature : %s\n", l.hdr.signature); STDERR(" header_version : %d\n", l.hdr.header_version); STDERR(" status : %d\n", l.hdr.status); STDERR(" block_size : %d\n", l.hdr.block_size); STDERR(" sub_hdr_size : %d\n", l.hdr.sub_hdr_size); STDERR(" bitmap_blocks : %d\n", l.hdr.bitmap_blocks); STDERR(" max_mapnr : 0x%x\n", l.hdr.max_mapnr); STDERR(" total_ram_blocks : %d\n", l.hdr.total_ram_blocks); STDERR(" device_blocks : %d\n", l.hdr.device_blocks); STDERR(" written_blocks : %d\n", l.hdr.written_blocks); STDERR(" current_cpu : %d\n", l.hdr.current_cpu); STDERR(" nr_cpus : %d\n", l.hdr.nr_cpus); } static void print_sub_header(void) { STDERR("kdump sub header\n"); STDERR(" phys_base : 0x%lx\n", l.shdr.phys_base); STDERR(" dump_level : %d\n", l.shdr.dump_level); STDERR(" split : %d\n", l.shdr.split); STDERR(" start_pfn : 0x%lx\n", l.shdr.start_pfn); STDERR(" end_pfn : 0x%lx\n", l.shdr.end_pfn); } #endif /* * Check for kdump flat end marker */ static inline int kdump_flat_endmarker(struct df_kdump_flat_data_hdr *d_hdr) { return (d_hdr->offs == -1) && (d_hdr->size == -1); } /* * Init kdump dump header */ static int init_kdump_hdr(struct df_kdump_hdr *hdr) { if (memcmp(hdr->signature, "KDUMP", 5) != 0) return -ENODEV; dfi_attr_version_set(hdr->header_version); dfi_attr_real_cpu_cnt_set(hdr->nr_cpus); dfi_attr_utsname_set(&hdr->utsname); dfi_attr_time_set(&hdr->timestamp); dfi_mem_chunk_add(0, (unsigned long) hdr->max_mapnr * PAGE_SIZE, NULL, NULL, NULL); return 0; } /* * Initialize kdump DFI */ static int dfi_kdump_init(void) { if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr))) return -ENODEV; if (zg_read(g.fh, &l.hdr, sizeof(l.hdr), ZG_CHECK_ERR) != sizeof(l.hdr)) return -ENODEV; if (memcmp(l.hdr.signature, "KDUMP", 5) != 0) return -ENODEV; zg_seek(g.fh, l.hdr.block_size, ZG_CHECK); zg_read(g.fh, &l.shdr, sizeof(l.shdr), ZG_CHECK); #ifdef DEBUG print_header(); print_sub_header(); #endif return init_kdump_hdr(&l.hdr); } /* * kdump DFI operations */ struct dfi dfi_kdump = { .name = "kdump", .init = dfi_kdump_init, .feat_bits = 0, }; #ifdef DEBUG static void print_kdump_flat_header(struct df_kdump_flat_hdr *hdr) { STDERR("diskdump main header\n"); STDERR(" signature : %s\n", hdr->signature); STDERR(" version : %lld\n", hdr->version); STDERR(" type : %lld\n", hdr->type); } #endif /* * Read makedumpfile dump header */ static int read_kdump_flat_hdr(void) { struct df_kdump_flat_hdr hdr; if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr))) return -ENODEV; if (zg_read(g.fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr)) return -ENODEV; if (memcmp(hdr.signature, "makedumpfile", 12) != 0) return -ENODEV; if (hdr.type != 1) return -ENODEV; #ifdef DEBUG print_kdump_flat_header(&hdr); #endif return 0; } /* * Read kdump header from fh */ static int read_kdump_hdr(struct zg_fh *fh, s64 size) { struct df_kdump_hdr hdr; if (size < (s64) sizeof(hdr)) ERR_EXIT("Can't get kdump header"); if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr)) return -EINVAL; if (init_kdump_hdr(&hdr)) return -EINVAL; zg_seek_cur(fh, -sizeof(hdr), ZG_CHECK_NONE); return 0; } /* * Initialize kdump_flat DFI */ static int dfi_kdump_flat_init(void) { struct df_kdump_flat_data_hdr d_hdr; if (read_kdump_flat_hdr() != 0) return -ENODEV; zg_seek(g.fh, 4096, ZG_CHECK); zg_read(g.fh, &d_hdr, sizeof(d_hdr), ZG_CHECK); do { if (d_hdr.offs == 0 && read_kdump_hdr(g.fh, d_hdr.size) != 0) return -EINVAL; zg_seek_cur(g.fh, d_hdr.size, ZG_CHECK_NONE); if (zg_read(g.fh, &d_hdr, sizeof(d_hdr), ZG_CHECK_ERR) != sizeof(d_hdr)) return -EINVAL; } while ((d_hdr.offs >= 0) && (d_hdr.size > 0)); if (kdump_flat_endmarker(&d_hdr)) return 0; return -EINVAL; } /* * kdump_flat DFI operations */ struct dfi dfi_kdump_flat = { .name = "kdump_flat", .init = dfi_kdump_flat_init, .feat_bits = 0, };