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

Commit a5e90b1b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ARM fixes from Russell King:
 "Further ARM fixes:
   - Anson Huang noticed that we were corrupting a register we shouldn't
     be during suspend on some CPUs.
   - Shengjiu Wang spotted a bug in the 'swp' instruction emulation.
   - Will Deacon fixed a bug in the ASID allocator.
   - Laura Abbott fixed the kernel permission protection to apply to all
     threads running in the system.
   - I've fixed two bugs with the domain access control register
     handling, one to do with printing an appropriate value at oops
     time, and the other to further fix the uaccess_with_memcpy code"

* 'fixes' of git://ftp.arm.linux.org.uk/~rmk/linux-arm:
  ARM: 8475/1: SWP emulation: Restore original *data when failed
  ARM: 8471/1: need to save/restore arm register(r11) when it is corrupted
  ARM: fix uaccess_with_memcpy() with SW_DOMAIN_PAN
  ARM: report proper DACR value in oops dumps
  ARM: 8464/1: Update all mm structures with section adjustments
  ARM: 8465/1: mm: keep reserved ASIDs in sync with mm after multiple rollovers
parents edb42dc7 34bfbae3
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -510,10 +510,14 @@ __copy_to_user_std(void __user *to, const void *from, unsigned long n);
static inline unsigned long __must_check
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
#ifndef CONFIG_UACCESS_WITH_MEMCPY
	unsigned int __ua_flags = uaccess_save_and_enable();
	n = arm_copy_to_user(to, from, n);
	uaccess_restore(__ua_flags);
	return n;
#else
	return arm_copy_to_user(to, from, n);
#endif
}

extern unsigned long __must_check
+18 −15
Original line number Diff line number Diff line
@@ -95,6 +95,22 @@ void __show_regs(struct pt_regs *regs)
{
	unsigned long flags;
	char buf[64];
#ifndef CONFIG_CPU_V7M
	unsigned int domain;
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
	/*
	 * Get the domain register for the parent context. In user
	 * mode, we don't save the DACR, so lets use what it should
	 * be. For other modes, we place it after the pt_regs struct.
	 */
	if (user_mode(regs))
		domain = DACR_UACCESS_ENABLE;
	else
		domain = *(unsigned int *)(regs + 1);
#else
	domain = get_domain();
#endif
#endif

	show_regs_print_info(KERN_DEFAULT);

@@ -123,21 +139,8 @@ void __show_regs(struct pt_regs *regs)

#ifndef CONFIG_CPU_V7M
	{
		unsigned int domain = get_domain();
		const char *segment;

#ifdef CONFIG_CPU_SW_DOMAIN_PAN
		/*
		 * Get the domain register for the parent context. In user
		 * mode, we don't save the DACR, so lets use what it should
		 * be. For other modes, we place it after the pt_regs struct.
		 */
		if (user_mode(regs))
			domain = DACR_UACCESS_ENABLE;
		else
			domain = *(unsigned int *)(regs + 1);
#endif

		if ((domain & domain_mask(DOMAIN_USER)) ==
		    domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
			segment = "none";
@@ -163,11 +166,11 @@ void __show_regs(struct pt_regs *regs)
		buf[0] = '\0';
#ifdef CONFIG_CPU_CP15_MMU
		{
			unsigned int transbase, dac = get_domain();
			unsigned int transbase;
			asm("mrc p15, 0, %0, c2, c0\n\t"
			    : "=r" (transbase));
			snprintf(buf, sizeof(buf), "  Table: %08x  DAC: %08x",
			  	transbase, dac);
				transbase, domain);
		}
#endif
		asm("mrc p15, 0, %0, c1, c0\n" : "=r" (ctrl));
+3 −3
Original line number Diff line number Diff line
@@ -36,10 +36,10 @@
 */
#define __user_swpX_asm(data, addr, res, temp, B)		\
	__asm__ __volatile__(					\
	"	mov		%2, %1\n"			\
	"0:	ldrex"B"	%1, [%3]\n"			\
	"1:	strex"B"	%0, %2, [%3]\n"			\
	"0:	ldrex"B"	%2, [%3]\n"			\
	"1:	strex"B"	%0, %1, [%3]\n"			\
	"	cmp		%0, #0\n"			\
	"	moveq		%1, %2\n"			\
	"	movne		%0, %4\n"			\
	"2:\n"							\
	"	.section	 .text.fixup,\"ax\"\n"		\
+23 −6
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
static unsigned long noinline
__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
{
	unsigned long ua_flags;
	int atomic;

	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
@@ -118,7 +119,9 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
		if (tocopy > n)
			tocopy = n;

		ua_flags = uaccess_save_and_enable();
		memcpy((void *)to, from, tocopy);
		uaccess_restore(ua_flags);
		to += tocopy;
		from += tocopy;
		n -= tocopy;
@@ -145,14 +148,21 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
	 * With frame pointer disabled, tail call optimization kicks in
	 * as well making this test almost invisible.
	 */
	if (n < 64)
		return __copy_to_user_std(to, from, n);
	return __copy_to_user_memcpy(to, from, n);
	if (n < 64) {
		unsigned long ua_flags = uaccess_save_and_enable();
		n = __copy_to_user_std(to, from, n);
		uaccess_restore(ua_flags);
	} else {
		n = __copy_to_user_memcpy(to, from, n);
	}
	return n;
}
	
static unsigned long noinline
__clear_user_memset(void __user *addr, unsigned long n)
{
	unsigned long ua_flags;

	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
		memset((void *)addr, 0, n);
		return 0;
@@ -175,7 +185,9 @@ __clear_user_memset(void __user *addr, unsigned long n)
		if (tocopy > n)
			tocopy = n;

		ua_flags = uaccess_save_and_enable();
		memset((void *)addr, 0, tocopy);
		uaccess_restore(ua_flags);
		addr += tocopy;
		n -= tocopy;

@@ -193,9 +205,14 @@ __clear_user_memset(void __user *addr, unsigned long n)
unsigned long arm_clear_user(void __user *addr, unsigned long n)
{
	/* See rational for this in __copy_to_user() above. */
	if (n < 64)
		return __clear_user_std(addr, n);
	return __clear_user_memset(addr, n);
	if (n < 64) {
		unsigned long ua_flags = uaccess_save_and_enable();
		n = __clear_user_std(addr, n);
		uaccess_restore(ua_flags);
	} else {
		n = __clear_user_memset(addr, n);
	}
	return n;
}

#if 0
+26 −12
Original line number Diff line number Diff line
@@ -165,13 +165,28 @@ static void flush_context(unsigned int cpu)
		__flush_icache_all();
}

static int is_reserved_asid(u64 asid)
static bool check_update_reserved_asid(u64 asid, u64 newasid)
{
	int cpu;
	for_each_possible_cpu(cpu)
		if (per_cpu(reserved_asids, cpu) == asid)
			return 1;
	return 0;
	bool hit = false;

	/*
	 * Iterate over the set of reserved ASIDs looking for a match.
	 * If we find one, then we can update our mm to use newasid
	 * (i.e. the same ASID in the current generation) but we can't
	 * exit the loop early, since we need to ensure that all copies
	 * of the old ASID are updated to reflect the mm. Failure to do
	 * so could result in us missing the reserved ASID in a future
	 * generation.
	 */
	for_each_possible_cpu(cpu) {
		if (per_cpu(reserved_asids, cpu) == asid) {
			hit = true;
			per_cpu(reserved_asids, cpu) = newasid;
		}
	}

	return hit;
}

static u64 new_context(struct mm_struct *mm, unsigned int cpu)
@@ -181,12 +196,14 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
	u64 generation = atomic64_read(&asid_generation);

	if (asid != 0) {
		u64 newasid = generation | (asid & ~ASID_MASK);

		/*
		 * If our current ASID was active during a rollover, we
		 * can continue to use it and this was just a false alarm.
		 */
		if (is_reserved_asid(asid))
			return generation | (asid & ~ASID_MASK);
		if (check_update_reserved_asid(asid, newasid))
			return newasid;

		/*
		 * We had a valid ASID in a previous life, so try to re-use
@@ -194,7 +211,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
		 */
		asid &= ~ASID_MASK;
		if (!__test_and_set_bit(asid, asid_map))
			goto bump_gen;
			return newasid;
	}

	/*
@@ -216,11 +233,8 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)

	__set_bit(asid, asid_map);
	cur_idx = asid;

bump_gen:
	asid |= generation;
	cpumask_clear(mm_cpumask(mm));
	return asid;
	return asid | generation;
}

void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
Loading