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

Commit d039837a authored by Max Filippov's avatar Max Filippov Committed by Greg Kroah-Hartman
Browse files

xtensa: enable coprocessors that are being flushed



commit 2958b66694e018c552be0b60521fec27e8d12988 upstream.

coprocessor_flush_all may be called from a context of a thread that is
different from the thread being flushed. In that case contents of the
cpenable special register may not match ti->cpenable of the target
thread, resulting in unhandled coprocessor exception in the kernel
context.
Set cpenable special register to the ti->cpenable of the target register
for the duration of the flush and restore it afterwards.
This fixes the following crash caused by coprocessor register inspection
in native gdb:

  (gdb) p/x $w0
  Illegal instruction in kernel: sig: 9 [#1] PREEMPT
  Call Trace:
    ___might_sleep+0x184/0x1a4
    __might_sleep+0x41/0xac
    exit_signals+0x14/0x218
    do_exit+0xc9/0x8b8
    die+0x99/0xa0
    do_illegal_instruction+0x18/0x6c
    common_exception+0x77/0x77
    coprocessor_flush+0x16/0x3c
    arch_ptrace+0x46c/0x674
    sys_ptrace+0x2ce/0x3b4
    system_call+0x54/0x80
    common_exception+0x77/0x77
  note: gdb[100] exited with preempt_count 1
  Killed

Cc: stable@vger.kernel.org
Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 83f00ab9
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -88,18 +88,21 @@ void coprocessor_release_all(struct thread_info *ti)

void coprocessor_flush_all(struct thread_info *ti)
{
	unsigned long cpenable;
	unsigned long cpenable, old_cpenable;
	int i;

	preempt_disable();

	RSR_CPENABLE(old_cpenable);
	cpenable = ti->cpenable;
	WSR_CPENABLE(cpenable);

	for (i = 0; i < XCHAL_CP_MAX; i++) {
		if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
			coprocessor_flush(ti, i);
		cpenable >>= 1;
	}
	WSR_CPENABLE(old_cpenable);

	preempt_enable();
}