Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df9694c7 authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ u32 os_info_csum(struct os_info *os_info);

#ifdef CONFIG_CRASH_DUMP
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
static inline void *os_info_old_entry(int nr, unsigned long *size)
{
+2 −1
Original line number Diff line number Diff line
@@ -77,7 +77,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
void sclp_get_ipl_info(struct sclp_ipl_info *info);
int sclp_pci_configure(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);
int _sclp_print_early(const char *);

+79 −92
Original line number Diff line number Diff line
@@ -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)
		return 0;
	if (!is_vmalloc_or_module_addr(dest))
		return memcpy_real(dest, src, count);
	do {
		size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK));
		if (memcpy_real(load_real_addr(dest), src, size))
	while (count) {
		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_kernel(dst, from, len);
			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;
		count -= size;
		dest += size;
		src += size;
	} while (count);
		}
		dst += len;
		src += len;
		count -= len;
	}
	return 0;
}

/*
 * Copy one page from zfcpdump "oldmem"
 *
 * For pages below HSA size memory from the HSA is copied. Otherwise
 * real memory copy is used.
 * Copy memory of the old, dumped system to a user space virtual address
 */
static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
					 unsigned long src, int userbuf)
int copy_oldmem_user(void __user *dst, void *src, size_t count)
{
	unsigned long from, len;
	int rc;

	if (src < sclp.hsa_size) {
		rc = memcpy_hsa(buf, src, csize, userbuf);
	while (count) {
		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 {
		if (userbuf)
			rc = copy_to_user_real((void __force __user *) buf,
					       (void *) src, csize);
		else
			rc = memcpy_real(buf, (void *) src, csize);
			/* 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;
			}
	return rc ? rc : csize;
			rc = copy_to_user_real(dst, (void *) from, count);
			if (rc)
				return rc;
		}

/*
 * Copy one page from kdump "oldmem"
 *
 * For the kdump reserved memory this functions performs a swap operation:
 *  - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
 *  - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 */
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;
		dst += len;
		src += len;
		count -= len;
	}
	return 0;
}

/*
@@ -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,
			 unsigned long offset, int userbuf)
{
	unsigned long src;
	void *src;
	int rc;

	if (!csize)
		return 0;
	src = (pfn << PAGE_SHIFT) + offset;
	if (OLDMEM_BASE)
		return copy_oldmem_page_kdump(buf, csize, src, userbuf);
	src = (void *) (pfn << PAGE_SHIFT) + offset;
	if (userbuf)
		rc = copy_oldmem_user((void __force __user *) buf, src, csize);
	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,
						       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
 */
@@ -425,17 +411,18 @@ static void *get_vmcoreinfo_old(unsigned long *size)
	Elf64_Nhdr note;
	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;
	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;
	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;
	if (strcmp(nt_name, "VMCOREINFO") != 0)
		return NULL;
	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;
	*size = note.n_descsz;
	return vmcoreinfo;
+4 −3
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ static void os_info_old_alloc(int nr, int align)
		goto fail;
	}
	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";
		goto fail_free;
	}
@@ -122,14 +122,15 @@ static void os_info_old_init(void)
		return;
	if (!OLDMEM_BASE)
		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;
	if (addr == 0 || addr % PAGE_SIZE)
		goto fail;
	os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
	if (!os_info_old)
		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;
	if (os_info_old->magic != OS_INFO_MAGIC)
		goto fail_free;
+2 −2
Original line number Diff line number Diff line
@@ -546,8 +546,8 @@ static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext,

	if (is_boot_cpu) {
		/* Copy the registers of the boot CPU. */
		copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
				 SAVE_AREA_BASE - PAGE_SIZE, 0);
		copy_oldmem_kernel(&sa_ext->sa, (void *) SAVE_AREA_BASE,
				   sizeof(sa_ext->sa));
		if (MACHINE_HAS_VX)
			save_vx_regs_safe(sa_ext->vx_regs);
		return;
Loading