zcore.c
来自「linux 内核源代码」· C语言 代码 · 共 653 行 · 第 1/2 页
C
653 行
/* * zcore module to export memory content and register sets for creating system * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same * dump format as s390 standalone dumps. * * For more information please refer to Documentation/s390/zfcpdump.txt * * Copyright IBM Corp. 2003,2007 * Author(s): Michael Holzheu */#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/utsname.h>#include <linux/debugfs.h>#include <asm/ipl.h>#include <asm/sclp.h>#include <asm/setup.h>#include <asm/sigp.h>#include <asm/uaccess.h>#include <asm/debug.h>#include <asm/processor.h>#include <asm/irqflags.h>#include "sclp.h"#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)#define MSG(x...) printk( KERN_ALERT x )#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x )#define TO_USER 0#define TO_KERNEL 1enum arch_id { ARCH_S390 = 0, ARCH_S390X = 1,};/* dump system info */struct sys_info { enum arch_id arch; unsigned long sa_base; u32 sa_size; int cpu_map[NR_CPUS]; unsigned long mem_size; union save_area lc_mask;};static struct sys_info sys_info;static struct debug_info *zcore_dbf;static int hsa_available;static struct dentry *zcore_dir;static struct dentry *zcore_file;/* * Copy memory from HSA to kernel or user memory (not reentrant): * * @dest: Kernel or user buffer where memory should be copied to * @src: Start address within HSA where data should be copied * @count: Size of buffer, which should be copied * @mode: Either TO_KERNEL or TO_USER */static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode){ int offs, blk_num; static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); if (count == 0) return 0; /* copy first block */ offs = 0; if ((src % PAGE_SIZE) != 0) { blk_num = src / PAGE_SIZE + 2; if (sclp_sdias_copy(buf, blk_num, 1)) { TRACE("sclp_sdias_copy() failed\n"); return -EIO; } offs = min((PAGE_SIZE - (src % PAGE_SIZE)), count); if (mode == TO_USER) { if (copy_to_user((__force __user void*) dest, buf + (src % PAGE_SIZE), offs)) return -EFAULT; } else memcpy(dest, buf + (src % PAGE_SIZE), offs); } if (offs == count) goto out; /* copy middle */ for (; (offs + PAGE_SIZE) <= count; offs += PAGE_SIZE) { blk_num = (src + offs) / PAGE_SIZE + 2; if (sclp_sdias_copy(buf, blk_num, 1)) { TRACE("sclp_sdias_copy() failed\n"); return -EIO; } if (mode == TO_USER) { if (copy_to_user((__force __user void*) dest + offs, buf, PAGE_SIZE)) return -EFAULT; } else memcpy(dest + offs, buf, PAGE_SIZE); } if (offs == count) goto out; /* copy last block */ blk_num = (src + offs) / PAGE_SIZE + 2; if (sclp_sdias_copy(buf, blk_num, 1)) { TRACE("sclp_sdias_copy() failed\n"); return -EIO; } if (mode == TO_USER) { if (copy_to_user((__force __user void*) dest + offs, buf, PAGE_SIZE)) return -EFAULT; } else memcpy(dest + offs, buf, count - offs);out: return 0;}static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count){ return memcpy_hsa((void __force *) dest, src, count, TO_USER);}static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count){ return memcpy_hsa(dest, src, count, TO_KERNEL);}static int memcpy_real(void *dest, unsigned long src, size_t count){ unsigned long flags; int rc = -EFAULT; register unsigned long _dest asm("2") = (unsigned long) dest; register unsigned long _len1 asm("3") = (unsigned long) count; register unsigned long _src asm("4") = src; register unsigned long _len2 asm("5") = (unsigned long) count; if (count == 0) return 0; flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ asm volatile ( "0: mvcle %1,%2,0x0\n" "1: jo 0b\n" " lhi %0,0x0\n" "2:\n" EX_TABLE(1b,2b) : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), "+d" (_len2), "=m" (*((long*)dest)) : "m" (*((long*)src)) : "cc", "memory"); __raw_local_irq_ssm(flags); return rc;}static int memcpy_real_user(void __user *dest, unsigned long src, size_t count){ static char buf[4096]; int offs = 0, size; while (offs < count) { size = min(sizeof(buf), count - offs); if (memcpy_real(buf, src + offs, size)) return -EFAULT; if (copy_to_user(dest + offs, buf, size)) return -EFAULT; offs += size; } return 0;}#ifdef __s390x__/* * Convert s390x (64 bit) cpu info to s390 (32 bit) cpu info */static void __init s390x_to_s390_regs(union save_area *out, union save_area *in, int cpu){ int i; for (i = 0; i < 16; i++) { out->s390.gp_regs[i] = in->s390x.gp_regs[i] & 0x00000000ffffffff; out->s390.acc_regs[i] = in->s390x.acc_regs[i]; out->s390.ctrl_regs[i] = in->s390x.ctrl_regs[i] & 0x00000000ffffffff; } /* locore for 31 bit has only space for fpregs 0,2,4,6 */ out->s390.fp_regs[0] = in->s390x.fp_regs[0]; out->s390.fp_regs[1] = in->s390x.fp_regs[2]; out->s390.fp_regs[2] = in->s390x.fp_regs[4]; out->s390.fp_regs[3] = in->s390x.fp_regs[6]; memcpy(&(out->s390.psw[0]), &(in->s390x.psw[0]), 4); out->s390.psw[1] |= 0x8; /* set bit 12 */ memcpy(&(out->s390.psw[4]),&(in->s390x.psw[12]), 4); out->s390.psw[4] |= 0x80; /* set (31bit) addressing bit */ out->s390.pref_reg = in->s390x.pref_reg; out->s390.timer = in->s390x.timer; out->s390.clk_cmp = in->s390x.clk_cmp;}static void __init s390x_to_s390_save_areas(void){ int i = 1; static union save_area tmp; while (zfcpdump_save_areas[i]) { s390x_to_s390_regs(&tmp, zfcpdump_save_areas[i], i); memcpy(zfcpdump_save_areas[i], &tmp, sizeof(tmp)); i++; }}#endif /* __s390x__ */static int __init init_cpu_info(enum arch_id arch){ union save_area *sa; /* get info for boot cpu from lowcore, stored in the HSA */ sa = kmalloc(sizeof(*sa), GFP_KERNEL); if (!sa) { ERROR_MSG("kmalloc failed: %s: %i\n",__FUNCTION__, __LINE__); return -ENOMEM; } if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) { ERROR_MSG("could not copy from HSA\n"); kfree(sa); return -EIO; } zfcpdump_save_areas[0] = sa;#ifdef __s390x__ /* convert s390x regs to s390, if we are dumping an s390 Linux */ if (arch == ARCH_S390) s390x_to_s390_save_areas();#endif return 0;}static DEFINE_MUTEX(zcore_mutex);#define DUMP_VERSION 0x3#define DUMP_MAGIC 0xa8190173618f23fdULL#define DUMP_ARCH_S390X 2#define DUMP_ARCH_S390 1#define HEADER_SIZE 4096/* dump header dumped according to s390 crash dump format */struct zcore_header { u64 magic; u32 version; u32 header_size; u32 dump_level; u32 page_size; u64 mem_size; u64 mem_start; u64 mem_end; u32 num_pages; u32 pad1; u64 tod; cpuid_t cpu_id; u32 arch_id; u32 volnr; u32 build_arch; u64 rmem_size; char pad2[4016];} __attribute__((packed,__aligned__(16)));static struct zcore_header zcore_header = { .magic = DUMP_MAGIC, .version = DUMP_VERSION, .header_size = 4096, .dump_level = 0, .page_size = PAGE_SIZE, .mem_start = 0,#ifdef __s390x__ .build_arch = DUMP_ARCH_S390X,#else .build_arch = DUMP_ARCH_S390,#endif};/* * Copy lowcore info to buffer. Use map in order to copy only register parts. * * @buf: User buffer * @sa: Pointer to save area * @sa_off: Offset in save area to copy * @len: Number of bytes to copy */static int copy_lc(void __user *buf, void *sa, int sa_off, int len){ int i; char *lc_mask = (char*)&sys_info.lc_mask; for (i = 0; i < len; i++) { if (!lc_mask[i + sa_off]) continue; if (copy_to_user(buf + i, sa + sa_off + i, 1)) return -EFAULT; } return 0;}/* * Copy lowcores info to memory, if necessary * * @buf: User buffer * @addr: Start address of buffer in dump memory * @count: Size of buffer */static int zcore_add_lc(char __user *buf, unsigned long start, size_t count){ unsigned long end; int i = 0; if (count == 0) return 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?