Commit df9694c7 authored by Martin Schwidefsky's avatar Martin Schwidefsky

s390/dump: streamline oldmem copy functions

Introduce two copy functions for the memory of the dumped system,
copy_oldmem_kernel() to copy to the virtual kernel address space
and copy_oldmem_user() to copy to user space.
Acked-by: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 8a07dd02
...@@ -38,7 +38,7 @@ u32 os_info_csum(struct os_info *os_info); ...@@ -38,7 +38,7 @@ u32 os_info_csum(struct os_info *os_info);
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
void *os_info_old_entry(int nr, unsigned long *size); void *os_info_old_entry(int nr, unsigned long *size);
int copy_from_oldmem(void *dest, void *src, size_t count); int copy_oldmem_kernel(void *dst, void *src, size_t count);
#else #else
static inline void *os_info_old_entry(int nr, unsigned long *size) static inline void *os_info_old_entry(int nr, unsigned long *size)
{ {
......
...@@ -77,7 +77,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info); ...@@ -77,7 +77,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
void sclp_get_ipl_info(struct sclp_ipl_info *info); void sclp_get_ipl_info(struct sclp_ipl_info *info);
int sclp_pci_configure(u32 fid); int sclp_pci_configure(u32 fid);
int sclp_pci_deconfigure(u32 fid); int sclp_pci_deconfigure(u32 fid);
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
void sclp_early_detect(void); void sclp_early_detect(void);
int _sclp_print_early(const char *); int _sclp_print_early(const char *);
......
...@@ -51,74 +51,85 @@ static inline void *load_real_addr(void *addr) ...@@ -51,74 +51,85 @@ static inline void *load_real_addr(void *addr)
} }
/* /*
* Copy real to virtual or real memory * Copy memory of the old, dumped system to a kernel space virtual address
*/ */
static int copy_from_realmem(void *dest, void *src, size_t count) int copy_oldmem_kernel(void *dst, void *src, size_t count)
{ {
unsigned long size; unsigned long from, len;
void *ra;
int rc;
if (!count) while (count) {
return 0; from = __pa(src);
if (!is_vmalloc_or_module_addr(dest)) if (!OLDMEM_BASE && from < sclp.hsa_size) {
return memcpy_real(dest, src, count); /* Copy from zfcpdump HSA area */
do { len = min(count, sclp.hsa_size - from);
size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK)); rc = memcpy_hsa_kernel(dst, from, len);
if (memcpy_real(load_real_addr(dest), src, size)) if (rc)
return rc;
} else {
/* Check for swapped kdump oldmem areas */
if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) {
from -= OLDMEM_BASE;
len = min(count, OLDMEM_SIZE - from);
} else if (OLDMEM_BASE && from < OLDMEM_SIZE) {
len = min(count, OLDMEM_SIZE - from);
from += OLDMEM_BASE;
} else {
len = count;
}
if (is_vmalloc_or_module_addr(dst)) {
ra = load_real_addr(dst);
len = min(PAGE_SIZE - offset_in_page(ra), len);
} else {
ra = dst;
}
if (memcpy_real(ra, (void *) from, len))
return -EFAULT; return -EFAULT;
count -= size; }
dest += size; dst += len;
src += size; src += len;
} while (count); count -= len;
}
return 0; return 0;
} }
/* /*
* Copy one page from zfcpdump "oldmem" * Copy memory of the old, dumped system to a user space virtual address
*
* For pages below HSA size memory from the HSA is copied. Otherwise
* real memory copy is used.
*/ */
static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize, int copy_oldmem_user(void __user *dst, void *src, size_t count)
unsigned long src, int userbuf)
{ {
unsigned long from, len;
int rc; int rc;
if (src < sclp.hsa_size) { while (count) {
rc = memcpy_hsa(buf, src, csize, userbuf); from = __pa(src);
if (!OLDMEM_BASE && from < sclp.hsa_size) {
/* Copy from zfcpdump HSA area */
len = min(count, sclp.hsa_size - from);
rc = memcpy_hsa_user(dst, from, len);
if (rc)
return rc;
} else { } else {
if (userbuf) /* Check for swapped kdump oldmem areas */
rc = copy_to_user_real((void __force __user *) buf, if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) {
(void *) src, csize); from -= OLDMEM_BASE;
else len = min(count, OLDMEM_SIZE - from);
rc = memcpy_real(buf, (void *) src, csize); } else if (OLDMEM_BASE && from < OLDMEM_SIZE) {
len = min(count, OLDMEM_SIZE - from);
from += OLDMEM_BASE;
} else {
len = count;
} }
return rc ? rc : csize; rc = copy_to_user_real(dst, (void *) from, count);
} if (rc)
return rc;
/* }
* Copy one page from kdump "oldmem" dst += len;
* src += len;
* For the kdump reserved memory this functions performs a swap operation: count -= len;
* - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE]. }
* - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] return 0;
*/
static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
unsigned long src, int userbuf)
{
int rc;
if (src < OLDMEM_SIZE)
src += OLDMEM_BASE;
else if (src > OLDMEM_BASE &&
src < OLDMEM_BASE + OLDMEM_SIZE)
src -= OLDMEM_BASE;
if (userbuf)
rc = copy_to_user_real((void __force __user *) buf,
(void *) src, csize);
else
rc = copy_from_realmem(buf, (void *) src, csize);
return (rc == 0) ? rc : csize;
} }
/* /*
...@@ -127,15 +138,17 @@ static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize, ...@@ -127,15 +138,17 @@ static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
unsigned long offset, int userbuf) unsigned long offset, int userbuf)
{ {
unsigned long src; void *src;
int rc;
if (!csize) if (!csize)
return 0; return 0;
src = (pfn << PAGE_SHIFT) + offset; src = (void *) (pfn << PAGE_SHIFT) + offset;
if (OLDMEM_BASE) if (userbuf)
return copy_oldmem_page_kdump(buf, csize, src, userbuf); rc = copy_oldmem_user((void __force __user *) buf, src, csize);
else else
return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf); rc = copy_oldmem_kernel((void *) buf, src, csize);
return rc;
} }
/* /*
...@@ -203,33 +216,6 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, ...@@ -203,33 +216,6 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
prot); prot);
} }
/*
* Copy memory from old kernel
*/
int copy_from_oldmem(void *dest, void *src, size_t count)
{
unsigned long copied = 0;
int rc;
if (OLDMEM_BASE) {
if ((unsigned long) src < OLDMEM_SIZE) {
copied = min(count, OLDMEM_SIZE - (unsigned long) src);
rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied);
if (rc)
return rc;
}
} else {
unsigned long hsa_end = sclp.hsa_size;
if ((unsigned long) src < hsa_end) {
copied = min(count, hsa_end - (unsigned long) src);
rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
if (rc)
return rc;
}
}
return copy_from_realmem(dest + copied, src + copied, count - copied);
}
/* /*
* Alloc memory and panic in case of ENOMEM * Alloc memory and panic in case of ENOMEM
*/ */
...@@ -425,17 +411,18 @@ static void *get_vmcoreinfo_old(unsigned long *size) ...@@ -425,17 +411,18 @@ static void *get_vmcoreinfo_old(unsigned long *size)
Elf64_Nhdr note; Elf64_Nhdr note;
void *addr; void *addr;
if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) if (copy_oldmem_kernel(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
return NULL; return NULL;
memset(nt_name, 0, sizeof(nt_name)); memset(nt_name, 0, sizeof(nt_name));
if (copy_from_oldmem(&note, addr, sizeof(note))) if (copy_oldmem_kernel(&note, addr, sizeof(note)))
return NULL; return NULL;
if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) if (copy_oldmem_kernel(nt_name, addr + sizeof(note),
sizeof(nt_name) - 1))
return NULL; return NULL;
if (strcmp(nt_name, "VMCOREINFO") != 0) if (strcmp(nt_name, "VMCOREINFO") != 0)
return NULL; return NULL;
vmcoreinfo = kzalloc_panic(note.n_descsz); vmcoreinfo = kzalloc_panic(note.n_descsz);
if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz))
return NULL; return NULL;
*size = note.n_descsz; *size = note.n_descsz;
return vmcoreinfo; return vmcoreinfo;
......
...@@ -89,7 +89,7 @@ static void os_info_old_alloc(int nr, int align) ...@@ -89,7 +89,7 @@ static void os_info_old_alloc(int nr, int align)
goto fail; goto fail;
} }
buf_align = PTR_ALIGN(buf, align); buf_align = PTR_ALIGN(buf, align);
if (copy_from_oldmem(buf_align, (void *) addr, size)) { if (copy_oldmem_kernel(buf_align, (void *) addr, size)) {
msg = "copy failed"; msg = "copy failed";
goto fail_free; goto fail_free;
} }
...@@ -122,14 +122,15 @@ static void os_info_old_init(void) ...@@ -122,14 +122,15 @@ static void os_info_old_init(void)
return; return;
if (!OLDMEM_BASE) if (!OLDMEM_BASE)
goto fail; goto fail;
if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr))) if (copy_oldmem_kernel(&addr, &S390_lowcore.os_info, sizeof(addr)))
goto fail; goto fail;
if (addr == 0 || addr % PAGE_SIZE) if (addr == 0 || addr % PAGE_SIZE)
goto fail; goto fail;
os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL); os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
if (!os_info_old) if (!os_info_old)
goto fail; goto fail;
if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old))) if (copy_oldmem_kernel(os_info_old, (void *) addr,
sizeof(*os_info_old)))
goto fail_free; goto fail_free;
if (os_info_old->magic != OS_INFO_MAGIC) if (os_info_old->magic != OS_INFO_MAGIC)
goto fail_free; goto fail_free;
......
...@@ -546,8 +546,8 @@ static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext, ...@@ -546,8 +546,8 @@ static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext,
if (is_boot_cpu) { if (is_boot_cpu) {
/* Copy the registers of the boot CPU. */ /* Copy the registers of the boot CPU. */
copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa), copy_oldmem_kernel(&sa_ext->sa, (void *) SAVE_AREA_BASE,
SAVE_AREA_BASE - PAGE_SIZE, 0); sizeof(sa_ext->sa));
if (MACHINE_HAS_VX) if (MACHINE_HAS_VX)
save_vx_regs_safe(sa_ext->vx_regs); save_vx_regs_safe(sa_ext->vx_regs);
return; return;
......
...@@ -64,7 +64,7 @@ static struct ipl_parameter_block *ipl_block; ...@@ -64,7 +64,7 @@ static struct ipl_parameter_block *ipl_block;
* @count: Size of buffer, which should be copied * @count: Size of buffer, which should be copied
* @mode: Either TO_KERNEL or TO_USER * @mode: Either TO_KERNEL or TO_USER
*/ */
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
{ {
int offs, blk_num; int offs, blk_num;
static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
...@@ -126,12 +126,26 @@ int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) ...@@ -126,12 +126,26 @@ int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
return 0; return 0;
} }
static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count) /*
* Copy memory from HSA to 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
*/
int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
{ {
return memcpy_hsa((void __force *) dest, src, count, TO_USER); return memcpy_hsa((void __force *) dest, src, count, TO_USER);
} }
static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) /*
* Copy memory from HSA to kernel 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
*/
int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
{ {
return memcpy_hsa(dest, src, count, TO_KERNEL); return memcpy_hsa(dest, src, count, TO_KERNEL);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment