root/drivers/s390/char/zcore.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. memcpy_hsa_user
  2. memcpy_hsa_kernel
  3. init_cpu_info
  4. release_hsa
  5. zcore_memmap_read
  6. zcore_memmap_open
  7. zcore_memmap_release
  8. zcore_reipl_write
  9. zcore_reipl_open
  10. zcore_reipl_release
  11. zcore_hsa_read
  12. zcore_hsa_write
  13. check_sdias
  14. zcore_reipl_init
  15. zcore_init

   1 // SPDX-License-Identifier: GPL-1.0+
   2 /*
   3  * zcore module to export memory content and register sets for creating system
   4  * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same
   5  * dump format as s390 standalone dumps.
   6  *
   7  * For more information please refer to Documentation/s390/zfcpdump.rst
   8  *
   9  * Copyright IBM Corp. 2003, 2008
  10  * Author(s): Michael Holzheu
  11  */
  12 
  13 #define KMSG_COMPONENT "zdump"
  14 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  15 
  16 #include <linux/init.h>
  17 #include <linux/slab.h>
  18 #include <linux/debugfs.h>
  19 #include <linux/memblock.h>
  20 
  21 #include <asm/asm-offsets.h>
  22 #include <asm/ipl.h>
  23 #include <asm/sclp.h>
  24 #include <asm/setup.h>
  25 #include <linux/uaccess.h>
  26 #include <asm/debug.h>
  27 #include <asm/processor.h>
  28 #include <asm/irqflags.h>
  29 #include <asm/checksum.h>
  30 #include <asm/os_info.h>
  31 #include <asm/switch_to.h>
  32 #include "sclp.h"
  33 
  34 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
  35 
  36 #define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */
  37 
  38 enum arch_id {
  39         ARCH_S390       = 0,
  40         ARCH_S390X      = 1,
  41 };
  42 
  43 struct ipib_info {
  44         unsigned long   ipib;
  45         u32             checksum;
  46 }  __attribute__((packed));
  47 
  48 static struct debug_info *zcore_dbf;
  49 static int hsa_available;
  50 static struct dentry *zcore_dir;
  51 static struct dentry *zcore_memmap_file;
  52 static struct dentry *zcore_reipl_file;
  53 static struct dentry *zcore_hsa_file;
  54 static struct ipl_parameter_block *zcore_ipl_block;
  55 
  56 static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
  57 
  58 /*
  59  * Copy memory from HSA to user memory (not reentrant):
  60  *
  61  * @dest:  User buffer where memory should be copied to
  62  * @src:   Start address within HSA where data should be copied
  63  * @count: Size of buffer, which should be copied
  64  */
  65 int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
  66 {
  67         unsigned long offset, bytes;
  68 
  69         if (!hsa_available)
  70                 return -ENODATA;
  71 
  72         while (count) {
  73                 if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
  74                         TRACE("sclp_sdias_copy() failed\n");
  75                         return -EIO;
  76                 }
  77                 offset = src % PAGE_SIZE;
  78                 bytes = min(PAGE_SIZE - offset, count);
  79                 if (copy_to_user(dest, hsa_buf + offset, bytes))
  80                         return -EFAULT;
  81                 src += bytes;
  82                 dest += bytes;
  83                 count -= bytes;
  84         }
  85         return 0;
  86 }
  87 
  88 /*
  89  * Copy memory from HSA to kernel memory (not reentrant):
  90  *
  91  * @dest:  Kernel or user buffer where memory should be copied to
  92  * @src:   Start address within HSA where data should be copied
  93  * @count: Size of buffer, which should be copied
  94  */
  95 int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
  96 {
  97         unsigned long offset, bytes;
  98 
  99         if (!hsa_available)
 100                 return -ENODATA;
 101 
 102         while (count) {
 103                 if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
 104                         TRACE("sclp_sdias_copy() failed\n");
 105                         return -EIO;
 106                 }
 107                 offset = src % PAGE_SIZE;
 108                 bytes = min(PAGE_SIZE - offset, count);
 109                 memcpy(dest, hsa_buf + offset, bytes);
 110                 src += bytes;
 111                 dest += bytes;
 112                 count -= bytes;
 113         }
 114         return 0;
 115 }
 116 
 117 static int __init init_cpu_info(void)
 118 {
 119         struct save_area *sa;
 120 
 121         /* get info for boot cpu from lowcore, stored in the HSA */
 122         sa = save_area_boot_cpu();
 123         if (!sa)
 124                 return -ENOMEM;
 125         if (memcpy_hsa_kernel(hsa_buf, __LC_FPREGS_SAVE_AREA, 512) < 0) {
 126                 TRACE("could not copy from HSA\n");
 127                 return -EIO;
 128         }
 129         save_area_add_regs(sa, hsa_buf); /* vx registers are saved in smp.c */
 130         return 0;
 131 }
 132 
 133 /*
 134  * Release the HSA
 135  */
 136 static void release_hsa(void)
 137 {
 138         diag308(DIAG308_REL_HSA, NULL);
 139         hsa_available = 0;
 140 }
 141 
 142 static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
 143                                  size_t count, loff_t *ppos)
 144 {
 145         return simple_read_from_buffer(buf, count, ppos, filp->private_data,
 146                                        memblock.memory.cnt * CHUNK_INFO_SIZE);
 147 }
 148 
 149 static int zcore_memmap_open(struct inode *inode, struct file *filp)
 150 {
 151         struct memblock_region *reg;
 152         char *buf;
 153         int i = 0;
 154 
 155         buf = kcalloc(memblock.memory.cnt, CHUNK_INFO_SIZE, GFP_KERNEL);
 156         if (!buf) {
 157                 return -ENOMEM;
 158         }
 159         for_each_memblock(memory, reg) {
 160                 sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ",
 161                         (unsigned long long) reg->base,
 162                         (unsigned long long) reg->size);
 163         }
 164         filp->private_data = buf;
 165         return nonseekable_open(inode, filp);
 166 }
 167 
 168 static int zcore_memmap_release(struct inode *inode, struct file *filp)
 169 {
 170         kfree(filp->private_data);
 171         return 0;
 172 }
 173 
 174 static const struct file_operations zcore_memmap_fops = {
 175         .owner          = THIS_MODULE,
 176         .read           = zcore_memmap_read,
 177         .open           = zcore_memmap_open,
 178         .release        = zcore_memmap_release,
 179         .llseek         = no_llseek,
 180 };
 181 
 182 static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
 183                                  size_t count, loff_t *ppos)
 184 {
 185         if (zcore_ipl_block) {
 186                 diag308(DIAG308_SET, zcore_ipl_block);
 187                 diag308(DIAG308_LOAD_CLEAR, NULL);
 188         }
 189         return count;
 190 }
 191 
 192 static int zcore_reipl_open(struct inode *inode, struct file *filp)
 193 {
 194         return stream_open(inode, filp);
 195 }
 196 
 197 static int zcore_reipl_release(struct inode *inode, struct file *filp)
 198 {
 199         return 0;
 200 }
 201 
 202 static const struct file_operations zcore_reipl_fops = {
 203         .owner          = THIS_MODULE,
 204         .write          = zcore_reipl_write,
 205         .open           = zcore_reipl_open,
 206         .release        = zcore_reipl_release,
 207         .llseek         = no_llseek,
 208 };
 209 
 210 static ssize_t zcore_hsa_read(struct file *filp, char __user *buf,
 211                               size_t count, loff_t *ppos)
 212 {
 213         static char str[18];
 214 
 215         if (hsa_available)
 216                 snprintf(str, sizeof(str), "%lx\n", sclp.hsa_size);
 217         else
 218                 snprintf(str, sizeof(str), "0\n");
 219         return simple_read_from_buffer(buf, count, ppos, str, strlen(str));
 220 }
 221 
 222 static ssize_t zcore_hsa_write(struct file *filp, const char __user *buf,
 223                                size_t count, loff_t *ppos)
 224 {
 225         char value;
 226 
 227         if (*ppos != 0)
 228                 return -EPIPE;
 229         if (copy_from_user(&value, buf, 1))
 230                 return -EFAULT;
 231         if (value != '0')
 232                 return -EINVAL;
 233         release_hsa();
 234         return count;
 235 }
 236 
 237 static const struct file_operations zcore_hsa_fops = {
 238         .owner          = THIS_MODULE,
 239         .write          = zcore_hsa_write,
 240         .read           = zcore_hsa_read,
 241         .open           = nonseekable_open,
 242         .llseek         = no_llseek,
 243 };
 244 
 245 static int __init check_sdias(void)
 246 {
 247         if (!sclp.hsa_size) {
 248                 TRACE("Could not determine HSA size\n");
 249                 return -ENODEV;
 250         }
 251         return 0;
 252 }
 253 
 254 /*
 255  * Provide IPL parameter information block from either HSA or memory
 256  * for future reipl
 257  */
 258 static int __init zcore_reipl_init(void)
 259 {
 260         struct ipib_info ipib_info;
 261         int rc;
 262 
 263         rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info));
 264         if (rc)
 265                 return rc;
 266         if (ipib_info.ipib == 0)
 267                 return 0;
 268         zcore_ipl_block = (void *) __get_free_page(GFP_KERNEL);
 269         if (!zcore_ipl_block)
 270                 return -ENOMEM;
 271         if (ipib_info.ipib < sclp.hsa_size)
 272                 rc = memcpy_hsa_kernel(zcore_ipl_block, ipib_info.ipib,
 273                                        PAGE_SIZE);
 274         else
 275                 rc = memcpy_real(zcore_ipl_block, (void *) ipib_info.ipib,
 276                                  PAGE_SIZE);
 277         if (rc || (__force u32)csum_partial(zcore_ipl_block, zcore_ipl_block->hdr.len, 0) !=
 278             ipib_info.checksum) {
 279                 TRACE("Checksum does not match\n");
 280                 free_page((unsigned long) zcore_ipl_block);
 281                 zcore_ipl_block = NULL;
 282         }
 283         return 0;
 284 }
 285 
 286 static int __init zcore_init(void)
 287 {
 288         unsigned char arch;
 289         int rc;
 290 
 291         if (ipl_info.type != IPL_TYPE_FCP_DUMP)
 292                 return -ENODATA;
 293         if (OLDMEM_BASE)
 294                 return -ENODATA;
 295 
 296         zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long));
 297         debug_register_view(zcore_dbf, &debug_sprintf_view);
 298         debug_set_level(zcore_dbf, 6);
 299 
 300         TRACE("devno:  %x\n", ipl_info.data.fcp.dev_id.devno);
 301         TRACE("wwpn:   %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn);
 302         TRACE("lun:    %llx\n", (unsigned long long) ipl_info.data.fcp.lun);
 303 
 304         rc = sclp_sdias_init();
 305         if (rc)
 306                 goto fail;
 307 
 308         rc = check_sdias();
 309         if (rc)
 310                 goto fail;
 311         hsa_available = 1;
 312 
 313         rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
 314         if (rc)
 315                 goto fail;
 316 
 317         if (arch == ARCH_S390) {
 318                 pr_alert("The 64-bit dump tool cannot be used for a "
 319                          "32-bit system\n");
 320                 rc = -EINVAL;
 321                 goto fail;
 322         }
 323 
 324         pr_alert("The dump process started for a 64-bit operating system\n");
 325         rc = init_cpu_info();
 326         if (rc)
 327                 goto fail;
 328 
 329         rc = zcore_reipl_init();
 330         if (rc)
 331                 goto fail;
 332 
 333         zcore_dir = debugfs_create_dir("zcore" , NULL);
 334         if (!zcore_dir) {
 335                 rc = -ENOMEM;
 336                 goto fail;
 337         }
 338         zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir,
 339                                                 NULL, &zcore_memmap_fops);
 340         if (!zcore_memmap_file) {
 341                 rc = -ENOMEM;
 342                 goto fail_dir;
 343         }
 344         zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
 345                                                 NULL, &zcore_reipl_fops);
 346         if (!zcore_reipl_file) {
 347                 rc = -ENOMEM;
 348                 goto fail_memmap_file;
 349         }
 350         zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir,
 351                                              NULL, &zcore_hsa_fops);
 352         if (!zcore_hsa_file) {
 353                 rc = -ENOMEM;
 354                 goto fail_reipl_file;
 355         }
 356         return 0;
 357 
 358 fail_reipl_file:
 359         debugfs_remove(zcore_reipl_file);
 360 fail_memmap_file:
 361         debugfs_remove(zcore_memmap_file);
 362 fail_dir:
 363         debugfs_remove(zcore_dir);
 364 fail:
 365         diag308(DIAG308_REL_HSA, NULL);
 366         return rc;
 367 }
 368 subsys_initcall(zcore_init);

/* [<][>][^][v][top][bottom][index][help] */