All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] sparc64: Handle additional cases of no fault loads
@ 2017-09-07 23:39 Rob Gardner
  2017-09-08 15:03 ` Sam Ravnborg
  2017-09-08 22:32 ` Rob Gardner
  0 siblings, 2 replies; 3+ messages in thread
From: Rob Gardner @ 2017-09-07 23:39 UTC (permalink / raw)
  To: sparclinux

Load instructions using ASI_PNF or other no-fault ASIs should not
cause a SIGSEGV or SIGBUS.

A garden variety unmapped address follows the TSB miss path, and when
no valid mapping is found in the process page tables, the miss handler
checks to see if the access was via a no-fault ASI.  It then fixes up
the target register with a zero, and skips the no-fault load
instruction.

But different paths are taken for data access exceptions and alignment
traps, and these do not respect the no-fault ASI. We add checks in
these paths for the no-fault ASI, and fix up the target register and
TPC just like in the TSB miss case.

Signed-off-by: Rob Gardner <rob.gardner@oracle.com>
---
 arch/sparc/kernel/traps_64.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index ad31af1..c49949c 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -265,6 +265,34 @@ void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
 	sun4v_insn_access_exception(regs, addr, type_ctx);
 }
 
+bool is_no_fault_exception(struct pt_regs *regs)
+{
+	unsigned char asi;
+	u32 insn;
+
+	if (get_user(insn, (u32 __user *)regs->tpc) = -EFAULT)
+		return false;
+
+	if ((insn & 0xc0800000) = 0xc0800000) {
+		if (insn & 0x2000)
+			asi = (regs->tstate >> 24);
+		else
+			asi = (insn >> 5);
+		if ((asi & 0xf2) = ASI_PNF) {
+			if (insn & 0x1000000) {
+				handle_ldf_stq(insn, regs);
+				return true;
+			} else if (insn & 0x200000) {
+				/* store instruction, do not handle */
+				return false;
+			}
+			handle_ld_nf(insn, regs);
+			return true;
+		}
+	}
+	return false;
+}
+
 void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
 	enum ctx_state prev_state = exception_enter();
@@ -296,6 +324,9 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un
 		die_if_kernel("Dax", regs);
 	}
 
+	if (is_no_fault_exception(regs))
+		return;
+
 	info.si_signo = SIGSEGV;
 	info.si_errno = 0;
 	info.si_code = SEGV_MAPERR;
@@ -352,6 +383,9 @@ void sun4v_data_access_exception(struct pt_regs *regs, unsigned long addr, unsig
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
+	if (is_no_fault_exception(regs))
+		return;
+
 	info.si_signo = SIGSEGV;
 	info.si_errno = 0;
 	info.si_code = SEGV_MAPERR;
@@ -2575,6 +2609,9 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo
 		kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
 		goto out;
 	}
+	if (is_no_fault_exception(regs))
+		return;
+
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRALN;
@@ -2597,6 +2634,9 @@ void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_c
 		kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
 		return;
 	}
+	if (is_no_fault_exception(regs))
+		return;
+
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRALN;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] sparc64: Handle additional cases of no fault loads
  2017-09-07 23:39 [PATCH] sparc64: Handle additional cases of no fault loads Rob Gardner
@ 2017-09-08 15:03 ` Sam Ravnborg
  2017-09-08 22:32 ` Rob Gardner
  1 sibling, 0 replies; 3+ messages in thread
From: Sam Ravnborg @ 2017-09-08 15:03 UTC (permalink / raw)
  To: sparclinux

Hi Rob.

> diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
> index ad31af1..c49949c 100644
> --- a/arch/sparc/kernel/traps_64.c
> +++ b/arch/sparc/kernel/traps_64.c
> @@ -265,6 +265,34 @@ void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
>  	sun4v_insn_access_exception(regs, addr, type_ctx);
>  }
>  
> +bool is_no_fault_exception(struct pt_regs *regs)
> +{
> +	unsigned char asi;
> +	u32 insn;
> +
> +	if (get_user(insn, (u32 __user *)regs->tpc) = -EFAULT)
> +		return false;
> +
> +	if ((insn & 0xc0800000) = 0xc0800000) {
> +		if (insn & 0x2000)
> +			asi = (regs->tstate >> 24);
> +		else
> +			asi = (insn >> 5);

The constants used in the above code is pure magic
for peopel without any initimate knowledge of sparc.
Could at a abre minimum add a few comments that explains
what is going on.


> +		if ((asi & 0xf2) = ASI_PNF) {
> +			if (insn & 0x1000000) {
> +				handle_ldf_stq(insn, regs);
> +				return true;
> +			} else if (insn & 0x200000) {
> +				/* store instruction, do not handle */
> +				return false;
> +			}
Likewise

> +			handle_ld_nf(insn, regs);
> +			return true;
> +		}
> +	}
> +	return false;
> +}

	Sam

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] sparc64: Handle additional cases of no fault loads
  2017-09-07 23:39 [PATCH] sparc64: Handle additional cases of no fault loads Rob Gardner
  2017-09-08 15:03 ` Sam Ravnborg
@ 2017-09-08 22:32 ` Rob Gardner
  1 sibling, 0 replies; 3+ messages in thread
From: Rob Gardner @ 2017-09-08 22:32 UTC (permalink / raw)
  To: sparclinux

On 09/08/2017 09:03 AM, Sam Ravnborg wrote:
> Hi Rob.
>
>> diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
>> index ad31af1..c49949c 100644
>> --- a/arch/sparc/kernel/traps_64.c
>> +++ b/arch/sparc/kernel/traps_64.c
>> @@ -265,6 +265,34 @@ void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
>>   	sun4v_insn_access_exception(regs, addr, type_ctx);
>>   }
>>   
>> +bool is_no_fault_exception(struct pt_regs *regs)
>> +{
>> +	unsigned char asi;
>> +	u32 insn;
>> +
>> +	if (get_user(insn, (u32 __user *)regs->tpc) = -EFAULT)
>> +		return false;
>> +
>> +	if ((insn & 0xc0800000) = 0xc0800000) {
>> +		if (insn & 0x2000)
>> +			asi = (regs->tstate >> 24);
>> +		else
>> +			asi = (insn >> 5);
> The constants used in the above code is pure magic
> for peopel without any initimate knowledge of sparc.
> Could at a abre minimum add a few comments that explains
> what is going on.

Thanks for pointing this out. I was trying to keep the code close to 
that found in do_kernel_fault(), but I agree it would be better to add 
some explanatory comments. Will revise.

Rob


>
>
>> +		if ((asi & 0xf2) = ASI_PNF) {
>> +			if (insn & 0x1000000) {
>> +				handle_ldf_stq(insn, regs);
>> +				return true;
>> +			} else if (insn & 0x200000) {
>> +				/* store instruction, do not handle */
>> +				return false;
>> +			}
> Likewise
>
>> +			handle_ld_nf(insn, regs);
>> +			return true;
>> +		}
>> +	}
>> +	return false;
>> +}
> 	Sam
> --
> To unsubscribe from this list: send the line "unsubscribe sparclinux" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-09-08 22:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-07 23:39 [PATCH] sparc64: Handle additional cases of no fault loads Rob Gardner
2017-09-08 15:03 ` Sam Ravnborg
2017-09-08 22:32 ` Rob Gardner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.