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

Commit 89a8c594 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull s390 fixes from Martin Schwidefsky:
 "An update for the BFP jit to the latest and greatest, two patches to
  get kdump working again, the random-abort ptrace extention for
  transactional execution, the z90crypt module alias for ap and a tiny
  cleanup"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/zcrypt: Alias for new zcrypt device driver base module
  s390/kdump: Allow copy_oldmem_page() copy to virtual memory
  s390/kdump: Disable mmap for s390
  s390/bpf,jit: add pkt_type support
  s390/bpf,jit: address randomize and write protect jit code
  s390/bpf,jit: use generic jit dumper
  s390/bpf,jit: call module_free() from any context
  s390/qdio: remove unused variable
  s390/ptrace: PTRACE_TE_ABORT_RAND
parents b8a33fc7 9da3545d
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -91,7 +91,15 @@ struct thread_struct {
#endif
};

#define PER_FLAG_NO_TE		1UL	/* Flag to disable transactions. */
/* Flag to disable transactions. */
#define PER_FLAG_NO_TE			1UL
/* Flag to enable random transaction aborts. */
#define PER_FLAG_TE_ABORT_RAND		2UL
/* Flag to specify random transaction abort mode:
 * - abort each transaction at a random instruction before TEND if set.
 * - abort random transactions at a random instruction if cleared.
 */
#define PER_FLAG_TE_ABORT_RAND_TEND	4UL

typedef struct thread_struct thread_struct;

+2 −2
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#include <linux/thread_info.h>

extern struct task_struct *__switch_to(void *, void *);
extern void update_per_regs(struct task_struct *task);
extern void update_cr_regs(struct task_struct *task);

static inline void save_fp_regs(s390_fp_regs *fpregs)
{
@@ -86,7 +86,7 @@ static inline void restore_access_regs(unsigned int *acrs)
		restore_fp_regs(&next->thread.fp_regs);			\
		restore_access_regs(&next->thread.acrs[0]);		\
		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
		update_per_regs(next);					\
		update_cr_regs(next);					\
	}								\
	prev = __switch_to(prev,next);					\
} while (0)
+1 −0
Original line number Diff line number Diff line
@@ -400,6 +400,7 @@ typedef struct
#define PTRACE_POKE_SYSTEM_CALL	      0x5008
#define PTRACE_ENABLE_TE	      0x5009
#define PTRACE_DISABLE_TE	      0x5010
#define PTRACE_TE_ABORT_RAND	      0x5011

/*
 * PT_PROT definition is loosely based on hppa bsd definition in
+47 −4
Original line number Diff line number Diff line
@@ -21,6 +21,48 @@
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))


/*
 * Return physical address for virtual address
 */
static inline void *load_real_addr(void *addr)
{
	unsigned long real_addr;

	asm volatile(
		   "	lra     %0,0(%1)\n"
		   "	jz	0f\n"
		   "	la	%0,0\n"
		   "0:"
		   : "=a" (real_addr) : "a" (addr) : "cc");
	return (void *)real_addr;
}

/*
 * Copy up to one page to vmalloc or real memory
 */
static ssize_t copy_page_real(void *buf, void *src, size_t csize)
{
	size_t size;

	if (is_vmalloc_addr(buf)) {
		BUG_ON(csize >= PAGE_SIZE);
		/* If buf is not page aligned, copy first part */
		size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize);
		if (size) {
			if (memcpy_real(load_real_addr(buf), src, size))
				return -EFAULT;
			buf += size;
			src += size;
		}
		/* Copy second part */
		size = csize - size;
		return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0;
	} else {
		return memcpy_real(buf, src, csize);
	}
}

/*
 * Copy one page from "oldmem"
 *
@@ -32,6 +74,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
			 size_t csize, unsigned long offset, int userbuf)
{
	unsigned long src;
	int rc;

	if (!csize)
		return 0;
@@ -43,11 +86,11 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
		 src < OLDMEM_BASE + OLDMEM_SIZE)
		src -= OLDMEM_BASE;
	if (userbuf)
		copy_to_user_real((void __force __user *) buf, (void *) src,
				  csize);
		rc = copy_to_user_real((void __force __user *) buf,
				       (void *) src, csize);
	else
		memcpy_real(buf, (void *) src, csize);
	return csize;
		rc = copy_page_real(buf, (void *) src, csize);
	return (rc == 0) ? csize : rc;
}

/*
+39 −11
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ enum s390_regset {
	REGSET_GENERAL_EXTENDED,
};

void update_per_regs(struct task_struct *task)
void update_cr_regs(struct task_struct *task)
{
	struct pt_regs *regs = task_pt_regs(task);
	struct thread_struct *thread = &task->thread;
@@ -56,17 +56,25 @@ void update_per_regs(struct task_struct *task)
#ifdef CONFIG_64BIT
	/* Take care of the enable/disable of transactional execution. */
	if (MACHINE_HAS_TE) {
		unsigned long cr0, cr0_new;
		unsigned long cr[3], cr_new[3];

		__ctl_store(cr0, 0, 0);
		/* set or clear transaction execution bits 8 and 9. */
		__ctl_store(cr, 0, 2);
		cr_new[1] = cr[1];
		/* Set or clear transaction execution TXC/PIFO bits 8 and 9. */
		if (task->thread.per_flags & PER_FLAG_NO_TE)
			cr0_new = cr0 & ~(3UL << 54);
			cr_new[0] = cr[0] & ~(3UL << 54);
		else
			cr0_new = cr0 | (3UL << 54);
		/* Only load control register 0 if necessary. */
		if (cr0 != cr0_new)
			__ctl_load(cr0_new, 0, 0);
			cr_new[0] = cr[0] | (3UL << 54);
		/* Set or clear transaction execution TDC bits 62 and 63. */
		cr_new[2] = cr[2] & ~3UL;
		if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
			if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
				cr_new[2] |= 1UL;
			else
				cr_new[2] |= 2UL;
		}
		if (memcmp(&cr_new, &cr, sizeof(cr)))
			__ctl_load(cr_new, 0, 2);
	}
#endif
	/* Copy user specified PER registers */
@@ -100,14 +108,14 @@ void user_enable_single_step(struct task_struct *task)
{
	set_tsk_thread_flag(task, TIF_SINGLE_STEP);
	if (task == current)
		update_per_regs(task);
		update_cr_regs(task);
}

void user_disable_single_step(struct task_struct *task)
{
	clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
	if (task == current)
		update_per_regs(task);
		update_cr_regs(task);
}

/*
@@ -447,6 +455,26 @@ long arch_ptrace(struct task_struct *child, long request,
		if (!MACHINE_HAS_TE)
			return -EIO;
		child->thread.per_flags |= PER_FLAG_NO_TE;
		child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND;
		return 0;
	case PTRACE_TE_ABORT_RAND:
		if (!MACHINE_HAS_TE || (child->thread.per_flags & PER_FLAG_NO_TE))
			return -EIO;
		switch (data) {
		case 0UL:
			child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND;
			break;
		case 1UL:
			child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND;
			child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND_TEND;
			break;
		case 2UL:
			child->thread.per_flags |= PER_FLAG_TE_ABORT_RAND;
			child->thread.per_flags &= ~PER_FLAG_TE_ABORT_RAND_TEND;
			break;
		default:
			return -EINVAL;
		}
		return 0;
	default:
		/* Removing high order bit from addr (only for 31 bit). */
Loading