• Rabin Vincent's avatar
    CRISv32: don't attempt syscall restart on irq exit · db4a35c6
    Rabin Vincent authored
    r9 is used to determine whether syscall restarting must be performed or
    not.  Unfortunately, r9 is never set to zero in the non-syscall path,
    and r9 is on top of that a callee-saved register which can be set to
    non-zero by the C functions that are called during IRQ handling.
    
    This means that if r10 (used for the syscall return value) is one of the
    -ERESTART* values when a hardware interrupt occurs which leads to a
    signal being delivered to the process, the kernel will "restart" a
    syscall which never occurred.  This will lead to the PC being moved back
    by 2 on return to user space.
    
    Fix the problem by setting r9 to zero in the interrupt path.
    
    Test case (should loop forever but ends up executing the break 8 trap
    instruction):
    
      #include <signal.h>
      #include <stdlib.h>
      #include <sys/time.h>
    
      void f(int n)
      {
      	register int r9 asm ("r9") = 1;
      	register int r10 asm ("r10") = n;
    
              __asm__ __volatile__(
      		"ba	1f	\n"
      		"nop		\n"
      		"break	8	\n"
      		"1: ba	.	\n"
      		"nop		\n"
      		:
      		: "r" (r9), "r" (r10)
      		: "memory");
      }
    
      void handler1(int sig) { }
    
      int main(int argc, char *argv[])
      {
              struct itimerval t1 = { .it_value = {1} };
    
              signal(SIGALRM, handler1);
              setitimer(ITIMER_REAL, &t1, NULL);
    
              f(-513); /* -ERESTARTNOINTR */
    
              return 0;
      }
    Signed-off-by: default avatarRabin Vincent <rabin@rab.in>
    Signed-off-by: default avatarJesper Nilsson <jespern@axis.com>
    db4a35c6
entry.S 22.6 KB