Commit a4785e93 authored by Michael Ellerman's avatar Michael Ellerman
Browse files

Merge branch 'fixes' into next

Merge our fixes branch which has a number of important fixes, notably
the fix for initrd corruption, as well as the fixes for scv vs ptrace.
parents ddf4a7bc 478036c4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -109,6 +109,16 @@ auxiliary vector.

scv 0 syscalls will always behave as PPC_FEATURE2_HTM_NOSC.

ptrace
------
When ptracing system calls (PTRACE_SYSCALL), the pt_regs.trap value contains
the system call type that can be used to distinguish between sc and scv 0
system calls, and the different register conventions can be accounted for.

If the value of (pt_regs.trap & 0xfff0) is 0xc00 then the system call was
performed with the sc instruction, if it is 0x3000 then the system call was
performed with the scv 0 instruction.

vsyscall
========

+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool
1098:	nop;					\
	.pushsection __jump_table, "aw";	\
	.long 1098b - ., LABEL - .;		\
	FTR_ENTRY_LONG KEY;			\
	FTR_ENTRY_LONG KEY - .;			\
	.popsection
#endif

+29 −0
Original line number Diff line number Diff line
@@ -31,6 +31,35 @@ static inline pte_t *find_init_mm_pte(unsigned long ea, unsigned *hshift)
	pgd_t *pgdir = init_mm.pgd;
	return __find_linux_pte(pgdir, ea, NULL, hshift);
}

/*
 * Convert a kernel vmap virtual address (vmalloc or ioremap space) to a
 * physical address, without taking locks. This can be used in real-mode.
 */
static inline phys_addr_t ppc_find_vmap_phys(unsigned long addr)
{
	pte_t *ptep;
	phys_addr_t pa;
	int hugepage_shift;

	/*
	 * init_mm does not free page tables, and does not do THP. It may
	 * have huge pages from huge vmalloc / ioremap etc.
	 */
	ptep = find_init_mm_pte(addr, &hugepage_shift);
	if (WARN_ON(!ptep))
		return 0;

	pa = PFN_PHYS(pte_pfn(*ptep));

	if (!hugepage_shift)
		hugepage_shift = PAGE_SHIFT;

	pa |= addr & ((1ul << hugepage_shift) - 1);

	return pa;
}

/*
 * This is what we should always use. Any other lockless page table lookup needs
 * careful audit against THP split.
+26 −19
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#ifndef _ASM_POWERPC_PTRACE_H
#define _ASM_POWERPC_PTRACE_H

#include <linux/err.h>
#include <uapi/asm/ptrace.h>
#include <asm/asm-const.h>

@@ -153,25 +154,6 @@ extern unsigned long profile_pc(struct pt_regs *regs);
long do_syscall_trace_enter(struct pt_regs *regs);
void do_syscall_trace_leave(struct pt_regs *regs);

#define kernel_stack_pointer(regs) ((regs)->gpr[1])
static inline int is_syscall_success(struct pt_regs *regs)
{
	return !(regs->ccr & 0x10000000);
}

static inline long regs_return_value(struct pt_regs *regs)
{
	if (is_syscall_success(regs))
		return regs->gpr[3];
	else
		return -regs->gpr[3];
}

static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
{
	regs->gpr[3] = rc;
}

#ifdef __powerpc64__
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
#else
@@ -236,6 +218,31 @@ static __always_inline void set_trap_norestart(struct pt_regs *regs)
	regs->trap |= 0x1;
}

#define kernel_stack_pointer(regs) ((regs)->gpr[1])
static inline int is_syscall_success(struct pt_regs *regs)
{
	if (trap_is_scv(regs))
		return !IS_ERR_VALUE((unsigned long)regs->gpr[3]);
	else
		return !(regs->ccr & 0x10000000);
}

static inline long regs_return_value(struct pt_regs *regs)
{
	if (trap_is_scv(regs))
		return regs->gpr[3];

	if (is_syscall_success(regs))
		return regs->gpr[3];
	else
		return -regs->gpr[3];
}

static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
{
	regs->gpr[3] = rc;
}

#define arch_has_single_step()	(1)
#define arch_has_block_step()	(true)
#define ARCH_HAS_USER_SINGLE_STEP_REPORT
+26 −16
Original line number Diff line number Diff line
@@ -41,12 +41,18 @@ static inline void syscall_rollback(struct task_struct *task,
static inline long syscall_get_error(struct task_struct *task,
				     struct pt_regs *regs)
{
	if (trap_is_scv(regs)) {
		unsigned long error = regs->gpr[3];

		return IS_ERR_VALUE(error) ? error : 0;
	} else {
		/*
		 * If the system call failed,
		 * regs->gpr[3] contains a positive ERRORCODE.
		 */
		return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
	}
}

static inline long syscall_get_return_value(struct task_struct *task,
					    struct pt_regs *regs)
@@ -58,11 +64,14 @@ static inline void syscall_set_return_value(struct task_struct *task,
					    struct pt_regs *regs,
					    int error, long val)
{
	if (trap_is_scv(regs)) {
		regs->gpr[3] = (long) error ?: val;
	} else {
		/*
	 * In the general case it's not obvious that we must deal with CCR
	 * here, as the syscall exit path will also do that for us. However
	 * there are some places, eg. the signal code, which check ccr to
	 * decide if the value in r3 is actually an error.
		 * In the general case it's not obvious that we must deal with
		 * CCR here, as the syscall exit path will also do that for us.
		 * However there are some places, eg. the signal code, which
		 * check ccr to decide if the value in r3 is actually an error.
		 */
		if (error) {
			regs->ccr |= 0x10000000L;
@@ -72,6 +81,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
			regs->gpr[3] = val;
		}
	}
}

static inline void syscall_get_arguments(struct task_struct *task,
					 struct pt_regs *regs,
Loading