Commit 2f0e8aae authored by Alexander Gordeev's avatar Alexander Gordeev Committed by Vasily Gorbik
Browse files

s390/mm: rework memcpy_real() to avoid DAT-off mode



Function memcpy_real() is an univeral data mover that does not
require DAT mode to be able reading from a physical address.
Its advantage is an ability to read from any address, even
those for which no kernel virtual mapping exists.

Although memcpy_real() is interrupt-safe, there are no handlers
that make use of this function. The compiler instrumentation
have to be disabled and separate no-DAT stack used to allow
execution of the function once DAT mode is disabled.

Rework memcpy_real() to overcome these shortcomings. As result,
data copying (which is primarily reading out a crashed system
memory by a user process) is executed on a regular stack with
enabled interrupts. Also, use of memcpy_real_buf swap buffer
becomes unnecessary and the swapping is eliminated.

The above is achieved by using a fixed virtual address range
that spans a single page and remaps that page repeatedly when
memcpy_real() is called for a particular physical address.

Reviewed-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 14a3a262
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

unsigned long __bootdata_preserved(__kaslr_offset);
unsigned long __bootdata_preserved(__abs_lowcore);
unsigned long __bootdata_preserved(__memcpy_real_area);
unsigned long __bootdata(__amode31_base);
unsigned long __bootdata_preserved(VMALLOC_START);
unsigned long __bootdata_preserved(VMALLOC_END);
@@ -182,7 +183,9 @@ static void setup_kernel_memory_layout(void)
	/* force vmalloc and modules below kasan shadow */
	vmax = min(vmax, KASAN_SHADOW_START);
#endif
	__abs_lowcore = round_down(vmax - ABS_LOWCORE_MAP_SIZE, sizeof(struct lowcore));
	__memcpy_real_area = round_down(vmax - PAGE_SIZE, PAGE_SIZE);
	__abs_lowcore = round_down(__memcpy_real_area - ABS_LOWCORE_MAP_SIZE,
				   sizeof(struct lowcore));
	MODULES_END = round_down(__abs_lowcore, _SEGMENT_SIZE);
	MODULES_VADDR = MODULES_END - MODULES_LEN;
	VMALLOC_END = MODULES_VADDR;
+14 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_S390_MACCESS_H
#define __ASM_S390_MACCESS_H

#include <linux/types.h>

struct iov_iter;

extern unsigned long __memcpy_real_area;
void memcpy_real_init(void);
size_t memcpy_real_iter(struct iov_iter *iter, unsigned long src, size_t count);
int memcpy_real(void *dest, unsigned long src, size_t count);

#endif /* __ASM_S390_MACCESS_H */
+1 −0
Original line number Diff line number Diff line
@@ -1780,6 +1780,7 @@ extern void vmem_remove_mapping(unsigned long start, unsigned long size);
extern int __vmem_map_4k_page(unsigned long addr, unsigned long phys, pgprot_t prot, bool alloc);
extern int vmem_map_4k_page(unsigned long addr, unsigned long phys, pgprot_t prot);
extern void vmem_unmap_4k_page(unsigned long addr);
extern pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc);
extern int s390_enable_sie(void);
extern int s390_enable_skey(void);
extern void s390_reset_cmma(struct mm_struct *mm);
+0 −2
Original line number Diff line number Diff line
@@ -306,8 +306,6 @@ static __always_inline void __noreturn disabled_wait(void)

#define ARCH_LOW_ADDRESS_LIMIT	0x7fffffffUL

extern int memcpy_real(void *, unsigned long, size_t);

extern int s390_isolate_bp(void);
extern int s390_isolate_bp_guest(void);

+2 −23
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <asm/elf.h>
#include <asm/ipl.h>
#include <asm/sclp.h>
#include <asm/maccess.h>

#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
@@ -53,8 +54,6 @@ struct save_area {
};

static LIST_HEAD(dump_save_areas);
static DEFINE_MUTEX(memcpy_real_mutex);
static char memcpy_real_buf[PAGE_SIZE];

/*
 * Allocate a save area
@@ -116,26 +115,6 @@ void __init save_area_add_vxrs(struct save_area *sa, __vector128 *vxrs)
	memcpy(sa->vxrs_high, vxrs + 16, 16 * sizeof(__vector128));
}

static size_t copy_to_iter_real(struct iov_iter *iter, unsigned long src, size_t count)
{
	size_t len, copied, res = 0;

	mutex_lock(&memcpy_real_mutex);
	while (count) {
		len = min(PAGE_SIZE, count);
		if (memcpy_real(memcpy_real_buf, src, len))
			break;
		copied = copy_to_iter(memcpy_real_buf, len, iter);
		count -= copied;
		src += copied;
		res += copied;
		if (copied < len)
			break;
	}
	mutex_unlock(&memcpy_real_mutex);
	return res;
}

size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count)
{
	size_t len, copied, res = 0;
@@ -156,7 +135,7 @@ size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count)
			} else {
				len = count;
			}
			copied = copy_to_iter_real(iter, src, len);
			copied = memcpy_real_iter(iter, src, len);
		}
		count -= copied;
		src += copied;
Loading