Skip to contentSkip to conversation

determining read or write on a page fault

Linux-ia64 Hoeflinger, Jay P 6 participants 16 messages Feb 21, 2002 – Apr 16, 2002

lore
Share & tools
lore
#0 lore raw

We are writing software that handles page faults on an Itanium system, and so have registered a SIGSEGV
handler. We think we know how to determine the address being referenced, but don't know how to determine
whether the access was a read or a write.

We believe that the handler entry point should be:

void
segv_handler(
int sig,
siginfo_t *sip,
struct sigcontext *scp)

and the address of the access therefore should be:

((caddr_t)sip->si_addr)

but how do we determine READ vs WRITE?

In IA-32 linux, we could check the PF_ERR bit. Is there an equivalent for IA-64?

Thanks

Naveen Neelakantam and Jay Hoeflinger

Jay Hoeflinger, [email protected]
KAI Software, A Division of Intel Americas, Inc., http://www.kai.com
Phone 217/356-2288, Direct 217/356-5052 x 140, Fax 217/356-5199

#1 lore raw

The code for retrieving the address is identical to what I use in our garbage collector.

According to David Mosberger, there is currently no way to distinguish between a read and a write fault. This is nontrivial to change because a SIGSEGV is sometimes generated in cases in which it is not clear which would be appropriate.

I suspect the best solution is to decode the faulting instruction sufficiently to distinguish loads from stores. I haven't written that code for Itanium, but my guess is that it's actually not that hard. David points out that this will fail if the code is not readable, e.g. if the fault occurred in the signal trampoline. (In any case, you need to deal with page faults in system calls separately, e.g. by avoiding them.)

Hans

Quoted 49 lines

-----Original Message-----
From: Hoeflinger, Jay P [mailto:[email protected]]
Sent: Thursday, February 21, 2002 1:10 PM
To: '[email protected]'
Subject: [Linux-ia64] determining read or write on a page fault

We are writing software that handles page faults on an Itanium system, and
so have registered a SIGSEGV
handler. We think we know how to determine the address being referenced,
but don't know how to determine
whether the access was a read or a write.

We believe that the handler entry point should be:

void
segv_handler(
int sig,
siginfo_t *sip,
struct sigcontext *scp)

and the address of the access therefore should be:

((caddr_t)sip->si_addr)

but how do we determine READ vs WRITE?

In IA-32 linux, we could check the PF_ERR bit. Is there an equivalent for
IA-64?

Thanks

Naveen Neelakantam and Jay Hoeflinger

Jay Hoeflinger, [email protected]
KAI Software, A Division of Intel Americas, Inc., http://www.kai.com
Phone 217/356-2288, Direct 217/356-5052 x 140, Fax 217/356-5199

_______________________________________________
Linux-IA64 mailing list
[email protected]
http://lists.linuxia64.org/lists/listinfo/linux-ia64

#2 lore raw
In reply to Hoeflinger, Jay P
Quoted 3 lines · Hans Boehm

According to David Mosberger, there is currently no way to distinguish between a read and a write fault. This is nontrivial to change because a SIGSEGV is sometimes generated in cases in which it is not clear which

would

Quoted 1 line

be appropriate.

Decoding the instruction seems really messy, but maybe I am not familiar enough with the Itanium architecture. Apparently the PC points to an instruction bundle and memory instructions can appear in both slots 0 and 1, meaning you have to do more than just determining whether a single instruction was a load or a store.

What if one slot has a load and the other a store? In that case you have to resort to matching the address with the address computed in the instruction, which can be in a register, but I don't know how to determine whether the current register contents are valid, or whether I have to find the register save area where the value was saved at the time of the fault. Additionally, there could be an immediate value that is added to the register contents, so the decoder code must compute the same address that the instruction computed before it can compare that to the address passed in sigcontext.

All of this sounds do-able, but it will take time to make sure the code mimics the address computation precisely.

What isn't do-able is to handle currently undefined op-codes. This means that when new instructions are added, existing binaries break and we have to revise the decoder.

In looking at the kernel page-fault code, we see that the memory access type is known at the time of signal dispatch, but then not passed through to the user's signal handler. Couldn't the kernel just pass the access type in sigcontext (this is how it was done in IA32)? In the event that the access type is not appropriate, then the access type could be tagged UNKNOWN.

It seems that this change to the page-fault code would be practically free since the information is already available, and it would save us (and others) from writing a difficult instruction-decoder that will break as soon as a new instruction is added to IPF.

Comments?

Jay

Jay Hoeflinger, [email protected]
KAI Software, A Division of Intel Americas, Inc., http://www.kai.com
Phone 217/356-2288, Direct 217/356-5052 x 140, Fax 217/356-5199

-----Original Message-----
From: Boehm, Hans [mailto:[email protected]]
Sent: Thursday, February 21, 2002 3:58 PM
To: 'Hoeflinger, Jay P'; '[email protected]'
Subject: RE: [Linux-ia64] determining read or write on a page fault

The code for retrieving the address is identical to what I use in our garbage collector.

According to David Mosberger, there is currently no way to distinguish between a read and a write fault. This is nontrivial to change because a SIGSEGV is sometimes generated in cases in which it is not clear which would be appropriate.

I suspect the best solution is to decode the faulting instruction sufficiently to distinguish loads from stores. I haven't written that code for Itanium, but my guess is that it's actually not that hard. David points out that this will fail if the code is not readable, e.g. if the fault occurred in the signal trampoline. (In any case, you need to deal with page faults in system calls separately, e.g. by avoiding them.)

Hans

Quoted 49 lines

-----Original Message-----
From: Hoeflinger, Jay P [mailto:[email protected]]
Sent: Thursday, February 21, 2002 1:10 PM
To: '[email protected]'
Subject: [Linux-ia64] determining read or write on a page fault

We are writing software that handles page faults on an Itanium system, and
so have registered a SIGSEGV
handler. We think we know how to determine the address being referenced,
but don't know how to determine
whether the access was a read or a write.

We believe that the handler entry point should be:

void
segv_handler(
int sig,
siginfo_t *sip,
struct sigcontext *scp)

and the address of the access therefore should be:

((caddr_t)sip->si_addr)

but how do we determine READ vs WRITE?

In IA-32 linux, we could check the PF_ERR bit. Is there an equivalent for
IA-64?

Thanks

Naveen Neelakantam and Jay Hoeflinger

Jay Hoeflinger, [email protected]
KAI Software, A Division of Intel Americas, Inc., http://www.kai.com
Phone 217/356-2288, Direct 217/356-5052 x 140, Fax 217/356-5199

_______________________________________________
Linux-IA64 mailing list
[email protected]
http://lists.linuxia64.org/lists/listinfo/linux-ia64

#3 lore raw
In reply to Hoeflinger, Jay P
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jay P

Jay> Decoding the instruction seems really messy, but maybe I am not Jay> familiar enough with the Itanium architecture.

It shouldn't be that bad. For a DSM, you only need to be able to reliably detect stores (everything else you can just assume to be loads).

Jay> Apparently the
Jay> PC points to an instruction bundle and memory instructions can Jay> appear in both slots 0 and 1, meaning you have to do more than Jay> just determining whether a single instruction was a load or a Jay> store.

Bits 0 and 1 in the IP stored in the sigcontext (sc_ip) encode the slot number 0, so you'll know exactly which instruction caused the fault.

Jay> What if one slot has a load and the other a store? In that Jay> case you have to resort to matching the address with the Jay> address computed in the instruction, which can be in a Jay> register, but I don't know how to determine whether the current Jay> register contents are valid, or whether I have to find the Jay> register save area where the value was saved at the time of the Jay> fault. Additionally, there could be an immediate value that is Jay> added to the register contents, so the decoder code must Jay> compute the same address that the instruction computed before Jay> it can compare that to the address passed in sigcontext.

None of that should be necessary.

Jay> All of this sounds do-able, but it will take time to make sure Jay> the code mimics the address computation precisely.

Jay> What isn't do-able is to handle currently undefined op-codes. Jay> This means that when new instructions are added, existing Jay> binaries break and we have to revise the decoder.

Jay> In looking at the kernel page-fault code, we see that the Jay> memory access type is known at the time of signal dispatch, but Jay> then not passed through to the user's signal handler. Couldn't Jay> the kernel just pass the access type in sigcontext (this is how Jay> it was done in IA32)? In the event that the access type is not Jay> appropriate, then the access type could be tagged UNKNOWN.

Yes, we can do that and I'm planning to make such a change. The solution Hans proposed is what you'd have to do if you need things working with today's kernels.

If you're willing to wait for a new kernel, I can send you a patch that adds the extra info to siginfo.

Jay> It seems that this change to the page-fault code would be Jay> practically free since the information is already available, Jay> and it would save us (and others) from writing a difficult Jay> instruction-decoder that will break as soon as a new Jay> instruction is added to IPF.

Yes, clearly that's preferable in the longer term. Nobody is objecting to doing this, it's just that nobody has gotten around to implementing it so far.

	--david
#4 lore raw
In reply to Hoeflinger, Jay P

So the slot number is in sigcontext! That makes things considerably easier. Does anyone have a piece of code that determines whether a given instruction is a load or a store?

Jay

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Friday, February 22, 2002 11:06 AM
To: Hoeflinger, Jay P
Cc: 'Boehm, Hans'; '[email protected]'
Subject: RE: [Linux-ia64] determining read or write on a page fault

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Fri, 22 Feb 2002 07:58:31 -0800, "Hoeflinger, Jay P"

<[email protected]> said:

Jay> Decoding the instruction seems really messy, but maybe I am not Jay> familiar enough with the Itanium architecture.

It shouldn't be that bad. For a DSM, you only need to be able to reliably detect stores (everything else you can just assume to be loads).

Jay> Apparently the
Jay> PC points to an instruction bundle and memory instructions can Jay> appear in both slots 0 and 1, meaning you have to do more than Jay> just determining whether a single instruction was a load or a Jay> store.

Bits 0 and 1 in the IP stored in the sigcontext (sc_ip) encode the slot number 0, so you'll know exactly which instruction caused the fault.

Jay> What if one slot has a load and the other a store? In that Jay> case you have to resort to matching the address with the Jay> address computed in the instruction, which can be in a Jay> register, but I don't know how to determine whether the current Jay> register contents are valid, or whether I have to find the Jay> register save area where the value was saved at the time of the Jay> fault. Additionally, there could be an immediate value that is Jay> added to the register contents, so the decoder code must Jay> compute the same address that the instruction computed before Jay> it can compare that to the address passed in sigcontext.

None of that should be necessary.

Jay> All of this sounds do-able, but it will take time to make sure Jay> the code mimics the address computation precisely.

Jay> What isn't do-able is to handle currently undefined op-codes. Jay> This means that when new instructions are added, existing Jay> binaries break and we have to revise the decoder.

Jay> In looking at the kernel page-fault code, we see that the Jay> memory access type is known at the time of signal dispatch, but Jay> then not passed through to the user's signal handler. Couldn't Jay> the kernel just pass the access type in sigcontext (this is how Jay> it was done in IA32)? In the event that the access type is not Jay> appropriate, then the access type could be tagged UNKNOWN.

Yes, we can do that and I'm planning to make such a change. The solution Hans proposed is what you'd have to do if you need things working with today's kernels.

If you're willing to wait for a new kernel, I can send you a patch that adds the extra info to siginfo.

Jay> It seems that this change to the page-fault code would be Jay> practically free since the information is already available, Jay> and it would save us (and others) from writing a difficult Jay> instruction-decoder that will break as soon as a new Jay> instruction is added to IPF.

Yes, clearly that's preferable in the longer term. Nobody is objecting to doing this, it's just that nobody has gotten around to implementing it so far.

	--david
#5 lore raw
In reply to Hoeflinger, Jay P

Jay-

Check out the unaligned fault handler in `arch/ia64/kernel/unaligned.c' That code should show you what you need to do.

Quoted 84 lines · Jay P

So the slot number is in sigcontext! That makes things considerably easier. Does anyone have a piece of code that determines whether a given instruction is a load or a store?

Jay

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Friday, February 22, 2002 11:06 AM
To: Hoeflinger, Jay P
Cc: 'Boehm, Hans'; '[email protected]'
Subject: RE: [Linux-ia64] determining read or write on a page fault

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Fri, 22 Feb 2002 07:58:31 -0800, "Hoeflinger, Jay P"

<[email protected]> said:

Jay> Decoding the instruction seems really messy, but maybe I am not Jay> familiar enough with the Itanium architecture.

It shouldn't be that bad. For a DSM, you only need to be able to reliably detect stores (everything else you can just assume to be loads).

Jay> Apparently the
Jay> PC points to an instruction bundle and memory instructions can Jay> appear in both slots 0 and 1, meaning you have to do more than Jay> just determining whether a single instruction was a load or a Jay> store.

Bits 0 and 1 in the IP stored in the sigcontext (sc_ip) encode the slot number 0, so you'll know exactly which instruction caused the fault.

Jay> What if one slot has a load and the other a store? In that Jay> case you have to resort to matching the address with the Jay> address computed in the instruction, which can be in a Jay> register, but I don't know how to determine whether the current Jay> register contents are valid, or whether I have to find the Jay> register save area where the value was saved at the time of the Jay> fault. Additionally, there could be an immediate value that is Jay> added to the register contents, so the decoder code must Jay> compute the same address that the instruction computed before Jay> it can compare that to the address passed in sigcontext.

None of that should be necessary.

Jay> All of this sounds do-able, but it will take time to make sure Jay> the code mimics the address computation precisely.

Jay> What isn't do-able is to handle currently undefined op-codes. Jay> This means that when new instructions are added, existing Jay> binaries break and we have to revise the decoder.

Jay> In looking at the kernel page-fault code, we see that the Jay> memory access type is known at the time of signal dispatch, but Jay> then not passed through to the user's signal handler. Couldn't Jay> the kernel just pass the access type in sigcontext (this is how Jay> it was done in IA32)? In the event that the access type is not Jay> appropriate, then the access type could be tagged UNKNOWN.

Yes, we can do that and I'm planning to make such a change. The solution Hans proposed is what you'd have to do if you need things working with today's kernels.

If you're willing to wait for a new kernel, I can send you a patch that adds the extra info to siginfo.

Jay> It seems that this change to the page-fault code would be Jay> practically free since the information is already available, Jay> and it would save us (and others) from writing a difficult Jay> instruction-decoder that will break as soon as a new Jay> instruction is added to IPF.

Yes, clearly that's preferable in the longer term. Nobody is objecting to doing this, it's just that nobody has gotten around to implementing it so far.

	--david

_______________________________________________
Linux-IA64 mailing list
[email protected]
http://lists.linuxia64.org/lists/listinfo/linux-ia64

Signature · 4 lines
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
[email protected]
Ph: 303/652-0870x117
#6 lore raw
In reply to Hoeflinger, Jay P
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · On Fri, 22 Feb 2002 10:29:16 -0700, [email protected] said:

Don> Jay- Check out the unaligned fault handler in
Don> `arch/ia64/kernel/unaligned.c' That code should show you what Don> you need to do.

The code in unaligned.c is far more complicated than what Jay would need. It'll take a few minutes of staring at the instruction encoding sections of the ia64 manual to figure out the most effective way for doing this, but just narrowing an instruction down to something that may do a store should be fairly easy (verify that the slot is an M slot, look at the most signicant bits of the instruction, ...). Don't forget about the semaphore instructions though!

	--david
#7 lore raw
In reply to Hoeflinger, Jay P

If you want to try with a new kernel, the attached patch should give you what you want. Specifically, if you get a SIGSEGV or a SIGBUS and si_code is non-zero, you can check si_flags. If it has the __ISR_VALID flag set, then the code in si_isr is valid. If si_isr is valid, you can check whether bit 34 (read exception) or bit 35 (non-access exception) is set. If so, you may assume that the signal was due to a load (or lfetch or some such). In all other cases, you'd have to play it safe and assume that you're dealing with a write access.

	--david
arch/ia64/ia32/ia32_support.c +4 -0
diff -urN linux-2.4.17/arch/ia64/ia32/ia32_support.c lia64-2.4/arch/ia64/ia32/ia32_support.c
@@ -172,6 +174,10 @@
 
 	siginfo.si_signo = SIGTRAP;
 	siginfo.si_errno = int_num;	/* XXX is it OK to abuse si_errno like this? */
+	siginfo.si_flags = 0;
+	siginfo.si_isr = 0;
+	siginfo.si_addr = 0;
+	siginfo.si_imm = 0;
 	siginfo.si_code = TRAP_BRKPT;
 	force_sig_info(SIGTRAP, &siginfo, current);
 }
arch/ia64/ia32/ia32_traps.c +7 -1
diff -urN linux-2.4.17/arch/ia64/ia32/ia32_traps.c lia64-2.4/arch/ia64/ia32/ia32_traps.c
@@ -2,7 +2,7 @@
  * IA-32 exception handlers
  *
  * Copyright (C) 2000 Asit K. Mallick <[email protected]>
- * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <[email protected]>
  *
  * 06/16/00	A. Mallick	added siginfo for most cases (close to IA32)
@@ -40,7 +40,11 @@
 {
 	struct siginfo siginfo;
 
+	/* initialize these fields to avoid leaking kernel bits to user space: */
 	siginfo.si_errno = 0;
+	siginfo.si_flags = 0;
+	siginfo.si_isr = 0;
+	siginfo.si_imm = 0;
 	switch ((isr >> 16) & 0xff) {
 	      case 1:
 	      case 2:
@@ -103,6 +107,8 @@
 			 * and it will suffer the consequences since we won't be able to
 			 * fully reproduce the context of the exception
 			 */
+			siginfo.si_isr = isr;
+			siginfo.si_flags = __ISR_VALID;
 			switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) {
 				case 0x000:
 				default:
arch/ia64/kernel/brl_emu.c +11 -0
diff -urN linux-2.4.17/arch/ia64/kernel/brl_emu.c lia64-2.4/arch/ia64/kernel/brl_emu.c
@@ -195,6 +195,9 @@
 		printk("Woah! Unimplemented Instruction Address Trap!\n");
 		siginfo.si_signo = SIGILL;
 		siginfo.si_errno = 0;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_imm = 0;
 		siginfo.si_code = ILL_BADIADDR;
 		force_sig_info(SIGILL, &siginfo, current);
 	} else if (ia64_psr(regs)->tb) {
@@ -205,6 +208,10 @@
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_code = TRAP_BRANCH;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_addr = 0;
+		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 	} else if (ia64_psr(regs)->ss) {
 		/*
@@ -214,6 +221,10 @@
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_code = TRAP_TRACE;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_addr = 0;
+		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 	}
 	return rv;
arch/ia64/kernel/signal.c +1 -0
diff -urN linux-2.4.17/arch/ia64/kernel/signal.c lia64-2.4/arch/ia64/kernel/signal.c
@@ -160,6 +160,7 @@
 		err |= __put_user((short)from->si_code, &to->si_code);
 		switch (from->si_code >> 16) {
 		      case __SI_FAULT >> 16:
+			err |= __put_user(from->si_flags, &to->si_flags);
 			err |= __put_user(from->si_isr, &to->si_isr);
 		      case __SI_POLL >> 16:
 			err |= __put_user(from->si_addr, &to->si_addr);
arch/ia64/kernel/traps.c +19 -1
diff -urN linux-2.4.17/arch/ia64/kernel/traps.c lia64-2.4/arch/ia64/kernel/traps.c
@@ -1,7 +1,7 @@
 /*
  * Architecture-specific trap handling.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <[email protected]>
  *
  * 05/12/00 grao <[email protected]> : added isr in siginfo for SIGFPE
@@ -133,6 +133,8 @@
 	/* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
 	siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
 	siginfo.si_imm = break_num;
+	siginfo.si_flags = 0;		/* clear __ISR_VALID */
+	siginfo.si_isr = 0;
 
 	switch (break_num) {
 	      case 0: /* unknown error */
@@ -352,6 +354,8 @@
 				siginfo.si_code = FPE_FLTDIV;
 			}
 			siginfo.si_isr = isr;
+			siginfo.si_flags = __ISR_VALID;
+			siginfo.si_imm = 0;
 			force_sig_info(SIGFPE, &siginfo, current);
 		}
 	} else {
@@ -372,6 +376,8 @@
 				siginfo.si_code = FPE_FLTRES;
 			}
 			siginfo.si_isr = isr;
+			siginfo.si_flags = __ISR_VALID;
+			siginfo.si_imm = 0;
 			force_sig_info(SIGFPE, &siginfo, current);
 		}
 	}
@@ -490,6 +496,8 @@
 			siginfo.si_errno = 0;
 			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
 			siginfo.si_imm = vector;
+			siginfo.si_flags = __ISR_VALID;
+			siginfo.si_isr = isr;
 			force_sig_info(SIGILL, &siginfo, current);
 			return;
 		}
@@ -517,6 +525,10 @@
 		}
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_addr = 0;
+		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 		return;
 
@@ -528,6 +540,9 @@
 			siginfo.si_errno = 0;
 			siginfo.si_code = FPE_FLTINV;
 			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+			siginfo.si_flags = __ISR_VALID;
+			siginfo.si_isr = isr;
+			siginfo.si_imm = 0;
 			force_sig_info(SIGFPE, &siginfo, current);
 		}
 		return;
@@ -537,6 +552,9 @@
 			siginfo.si_signo = SIGILL;
 			siginfo.si_code = ILL_BADIADDR;
 			siginfo.si_errno = 0;
+			siginfo.si_flags = 0;
+			siginfo.si_isr = 0;
+			siginfo.si_imm = 0;
 			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
 			force_sig_info(SIGILL, &siginfo, current);
 			return;
arch/ia64/kernel/unaligned.c +3 -0
diff -urN linux-2.4.17/arch/ia64/kernel/unaligned.c lia64-2.4/arch/ia64/kernel/unaligned.c
@@ -1488,6 +1488,9 @@
 	si.si_errno = 0;
 	si.si_code = BUS_ADRALN;
 	si.si_addr = (void *) ifa;
+	si.si_flags = 0;
+	si.si_isr = 0;
+	si.si_imm = 0;
 	force_sig_info(SIGBUS, &si, current);
 	goto done;
 }
arch/ia64/mm/fault.c +2 -0
diff -urN linux-2.4.17/arch/ia64/mm/fault.c lia64-2.4/arch/ia64/mm/fault.c
@@ -151,6 +151,8 @@
 		si.si_errno = 0;
 		si.si_code = code;
 		si.si_addr = (void *) address;
+		si.si_isr = isr;
+		si.si_flags = __ISR_VALID;
 		force_sig_info(signal, &si, current);
 		return;
 	}
include/asm-ia64/siginfo.h +15 -4
diff -urN linux-2.4.17/include/asm-ia64/siginfo.h lia64-2.4/include/asm-ia64/siginfo.h
@@ -2,8 +2,8 @@
 #define _ASM_IA64_SIGINFO_H
 
 /*
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <[email protected]>
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <[email protected]>
  */
 
 #include <linux/types.h>
@@ -57,7 +57,7 @@
 		struct {
 			void *_addr;		/* faulting insn/memory ref. */
 			int _imm;		/* immediate value for "break" */
-			int _pad0;
+			unsigned int _flags;	/* see below */
 			unsigned long _isr;	/* isr */
 		} _sigfault;
 
@@ -88,10 +88,21 @@
 #define si_ptr		_sifields._rt._sigval.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_imm		_sifields._sigfault._imm	/* as per UNIX SysV ABI spec */
-#define si_isr		_sifields._sigfault._isr	/* valid if si_code=FPE_FLTxxx */
+#define si_flags	_sifields._sigfault._flags
+/*
+ * si_isr is valid for SIGILL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP provided that
+ * si_code is non-zero and __ISR_VALID is set in si_flags.
+ */
+#define si_isr		_sifields._sigfault._isr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
 #define si_pfm_ovfl	_sifields._sigprof._pfm_ovfl_counters
+
+/*
+ * Flag values for si_flags:
+ */
+#define __ISR_VALID_BIT	0
+#define __ISR_VALID	(1 << __ISR_VALID_BIT)
 
 /*
  * si_code values
#8 lore raw
In reply to Hoeflinger, Jay P

Thanks, David. Which released version will this appear in?

Jay

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Friday, February 22, 2002 7:25 PM
To: Hoeflinger, Jay P
Cc: [email protected]
Subject: RE: [Linux-ia64] determining read or write on a page fault

If you want to try with a new kernel, the attached patch should give you what you want. Specifically, if you get a SIGSEGV or a SIGBUS and si_code is non-zero, you can check si_flags. If it has the __ISR_VALID flag set, then the code in si_isr is valid. If si_isr is valid, you can check whether bit 34 (read exception) or bit 35 (non-access exception) is set. If so, you may assume that the signal was due to a load (or lfetch or some such). In all other cases, you'd have to play it safe and assume that you're dealing with a write access.

	--david

diff -urN linux-2.4.17/arch/ia64/ia32/ia32_support.c lia64-2.4/arch/ia64/ia32/ia32_support.c

arch/ia64/ia32/ia32_support.c +0 -0
@@ -172,6 +174,10 @@
 
 	siginfo.si_signo = SIGTRAP;
 	siginfo.si_errno = int_num;	/* XXX is it OK to abuse si_errno

like this? */
+ siginfo.si_flags = 0;
+ siginfo.si_isr = 0;
+ siginfo.si_addr = 0;
+ siginfo.si_imm = 0;
siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current);
}
diff -urN linux-2.4.17/arch/ia64/ia32/ia32_traps.c lia64-2.4/arch/ia64/ia32/ia32_traps.c

arch/ia64/ia32/ia32_traps.c +2 -1
@@ -2,7 +2,7 @@
  * IA-32 exception handlers
  *
  * Copyright (C) 2000 Asit K. Mallick <[email protected]>
- * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <[email protected]>
  *
  * 06/16/00	A. Mallick	added siginfo for most cases (close to IA32)
@@ -40,7 +40,11 @@
 {
 	struct siginfo siginfo;
 
+	/* initialize these fields to avoid leaking kernel bits to user

space: */
siginfo.si_errno = 0;
+ siginfo.si_flags = 0;
+ siginfo.si_isr = 0;
+ siginfo.si_imm = 0;
switch ((isr >> 16) & 0xff) {
case 1:
case 2:
@@ -103,6 +107,8 @@
* and it will suffer the consequences since we
won't be able to
* fully reproduce the context of the exception */
+ siginfo.si_isr = isr;
+ siginfo.si_flags = __ISR_VALID;
switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) {
case 0x000:
default:
diff -urN linux-2.4.17/arch/ia64/kernel/brl_emu.c lia64-2.4/arch/ia64/kernel/brl_emu.c

arch/ia64/kernel/brl_emu.c +11 -0
@@ -195,6 +195,9 @@
 		printk("Woah! Unimplemented Instruction Address Trap!\n");
 		siginfo.si_signo = SIGILL;
 		siginfo.si_errno = 0;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_imm = 0;
 		siginfo.si_code = ILL_BADIADDR;
 		force_sig_info(SIGILL, &siginfo, current);
 	} else if (ia64_psr(regs)->tb) {
@@ -205,6 +208,10 @@
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_code = TRAP_BRANCH;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_addr = 0;
+		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 	} else if (ia64_psr(regs)->ss) {
 		/*
@@ -214,6 +221,10 @@
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_code = TRAP_TRACE;
+		siginfo.si_flags = 0;
+		siginfo.si_isr = 0;
+		siginfo.si_addr = 0;
+		siginfo.si_imm = 0;
 		force_sig_info(SIGTRAP, &siginfo, current);
 	}
 	return rv;

diff -urN linux-2.4.17/arch/ia64/kernel/signal.c
lia64-2.4/arch/ia64/kernel/signal.c

arch/ia64/kernel/signal.c +1 -0
@@ -160,6 +160,7 @@
 		err |= __put_user((short)from->si_code, &to->si_code);
 		switch (from->si_code >> 16) {
 		      case __SI_FAULT >> 16:
+			err |= __put_user(from->si_flags, &to->si_flags);
 			err |= __put_user(from->si_isr, &to->si_isr);
 		      case __SI_POLL >> 16:
 			err |= __put_user(from->si_addr, &to->si_addr);

diff -urN linux-2.4.17/arch/ia64/kernel/traps.c
lia64-2.4/arch/ia64/kernel/traps.c

arch/ia64/kernel/traps.c +1 -1
@@ -1,7 +1,7 @@
 /*
  * Architecture-specific trap handling.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <[email protected]>
  *
  * 05/12/00 grao <[email protected]> : added isr in siginfo for SIGFPE
@@ -133,6 +133,8 @@
 	/* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized:

*/
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = break_num;
+ siginfo.si_flags = 0; /* clear __ISR_VALID */
+ siginfo.si_isr = 0;

switch (break_num) {
case 0: /* unknown error */
@@ -352,6 +354,8 @@
siginfo.si_code = FPE_FLTDIV;
}
siginfo.si_isr = isr;
+ siginfo.si_flags = __ISR_VALID;
+ siginfo.si_imm = 0;
force_sig_info(SIGFPE, &siginfo, current);
}
} else {
@@ -372,6 +376,8 @@
siginfo.si_code = FPE_FLTRES;
}
siginfo.si_isr = isr;
+ siginfo.si_flags = __ISR_VALID;
+ siginfo.si_imm = 0;
force_sig_info(SIGFPE, &siginfo, current);
}
}
@@ -490,6 +496,8 @@
siginfo.si_errno = 0; siginfo.si_addr = (void *) (regs->cr_iip +
ia64_psr(regs)->ri);
siginfo.si_imm = vector;
+ siginfo.si_flags = __ISR_VALID;
+ siginfo.si_isr = isr;
force_sig_info(SIGILL, &siginfo, current); return;
}
@@ -517,6 +525,10 @@
}
siginfo.si_signo = SIGTRAP; siginfo.si_errno = 0;
+ siginfo.si_flags = 0;
+ siginfo.si_isr = 0;
+ siginfo.si_addr = 0;
+ siginfo.si_imm = 0;
force_sig_info(SIGTRAP, &siginfo, current); return;

@@ -528,6 +540,9 @@
siginfo.si_errno = 0; siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip +
ia64_psr(regs)->ri);
+ siginfo.si_flags = __ISR_VALID;
+ siginfo.si_isr = isr;
+ siginfo.si_imm = 0;
force_sig_info(SIGFPE, &siginfo, current);
}
return;
@@ -537,6 +552,9 @@
siginfo.si_signo = SIGILL; siginfo.si_code = ILL_BADIADDR; siginfo.si_errno = 0;
+ siginfo.si_flags = 0;
+ siginfo.si_isr = 0;
+ siginfo.si_imm = 0;
siginfo.si_addr = (void *) (regs->cr_iip +
ia64_psr(regs)->ri);
force_sig_info(SIGILL, &siginfo, current); return;
diff -urN linux-2.4.17/arch/ia64/kernel/unaligned.c lia64-2.4/arch/ia64/kernel/unaligned.c

arch/ia64/kernel/unaligned.c +3 -0
@@ -1488,6 +1488,9 @@
 	si.si_errno = 0;
 	si.si_code = BUS_ADRALN;
 	si.si_addr = (void *) ifa;
+	si.si_flags = 0;
+	si.si_isr = 0;
+	si.si_imm = 0;
 	force_sig_info(SIGBUS, &si, current);
 	goto done;
 }
arch/ia64/mm/fault.c +2 -0
diff -urN linux-2.4.17/arch/ia64/mm/fault.c lia64-2.4/arch/ia64/mm/fault.c
@@ -151,6 +151,8 @@
 		si.si_errno = 0;
 		si.si_code = code;
 		si.si_addr = (void *) address;
+		si.si_isr = isr;
+		si.si_flags = __ISR_VALID;
 		force_sig_info(signal, &si, current);
 		return;
 	}

diff -urN linux-2.4.17/include/asm-ia64/siginfo.h
lia64-2.4/include/asm-ia64/siginfo.h

include/asm-ia64/siginfo.h +2 -2
@@ -2,8 +2,8 @@
 #define _ASM_IA64_SIGINFO_H
 
 /*
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <[email protected]>
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <[email protected]>
  */
 
 #include <linux/types.h>
@@ -57,7 +57,7 @@
 		struct {
 			void *_addr;		/* faulting insn/memory ref.

*/
int _imm; /* immediate value for
"break" */
- int _pad0;
+ unsigned int _flags; /* see below */
unsigned long _isr; /* isr */
} _sigfault;

@@ -88,10 +88,21 @@
#define si_ptr _sifields._rt._sigval.sival_ptr
#define si_addr _sifields._sigfault._addr
#define si_imm _sifields._sigfault._imm /* as per UNIX SysV
ABI spec */
-#define si_isr _sifields._sigfault._isr /* valid if
si_code=FPE_FLTxxx */
+#define si_flags _sifields._sigfault._flags
+/*
+ * si_isr is valid for SIGILL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP provided that
+ * si_code is non-zero and __ISR_VALID is set in si_flags.
+ */
+#define si_isr _sifields._sigfault._isr
#define si_band _sifields._sigpoll._band
#define si_fd _sifields._sigpoll._fd
#define si_pfm_ovfl _sifields._sigprof._pfm_ovfl_counters
+
+/*
+ * Flag values for si_flags:
+ */
+#define __ISR_VALID_BIT 0
+#define __ISR_VALID (1 << __ISR_VALID_BIT)

/*
* si_code values

#9 lore raw
In reply to Hoeflinger, Jay P
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jay P

Jay> Thanks, David. Which released version will this appear Jay> in? Jay

I expect it to be in the ia64 patch for 2.4.18. It would be nice if you could test it and tell me whether it does what you want, though.

	--david
#10 lore raw
In reply to Hoeflinger, Jay P

We want to report success using the 2.4.18 kernel and the info sent to the segv handler on a page fault for our distributed virtual shared memory system on IA64. Thanks for your help. We had to make one assumption, though, that wasn't covered in your mail (below).

The assumption was that if si_code=0, that the access was a "read". We had originally assumed it was a "write", but this caused some errors. When we changed to assuming "read", things worked. Is this assumption valid? When does this case occur? Our scan of the kernel source seemed to indicate that this case can't happen.

Thanks

Jay Hoeflinger and Naveen Neelakantam

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Friday, February 22, 2002 7:25 PM
To: Hoeflinger, Jay P
Cc: [email protected]
Subject: RE: [Linux-ia64] determining read or write on a page fault

If you want to try with a new kernel, the attached patch should give you what you want. Specifically, if you get a SIGSEGV or a SIGBUS and si_code is non-zero, you can check si_flags. If it has the __ISR_VALID flag set, then the code in si_isr is valid. If si_isr is valid, you can check whether bit 34 (read exception) or bit 35 (non-access exception) is set. If so, you may assume that the signal was due to a load (or lfetch or some such). In all other cases, you'd have to play it safe and assume that you're dealing with a write access.

	--david

< patch deleted >

#11 lore raw
In reply to Hoeflinger, Jay P
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jay P

Jay> We want to report success using the 2.4.18 kernel and the info Jay> sent to the segv handler on a page fault for our distributed Jay> virtual shared memory system on IA64.

Great! Glad to hear that.

Jay> We had to make one assumption, though, that wasn't covered in Jay> your mail (below).

Jay> The assumption was that if si_code=0, that the access was a Jay> "read". We had originally assumed it was a "write", but this Jay> caused some errors. When we changed to assuming "read", things Jay> worked. Is this assumption valid? When does this case occur? Jay> Our scan of the kernel source seemed to indicate that this case Jay> can't happen.

Hmmh, that's a bit odd. If si_code is zero, we can't know what triggered the segfault. It could have been a read, a write, a semaphore instruction, or something entirely different (e.g., user sending SIGSEGV via kill(2)). Now, for a distributed shared memory system, I'd have thought that you'd want to treat such unknown accesses as writes, because otherwise the fault might re-occur as soon as the faulting instruction is restarted (since the page still doesn't have write permission). For normal cases (non-error cases/silly user cases), I wouldn't have expected this to occur. Do you know where those SIGSEGVs with si_code=0 were coming from?

	--david
#12 lore raw
In reply to Hoeflinger, Jay P

Not at the moment. :-)

We are looking into it.

Naveen

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Thursday, April 04, 2002 3:59 PM
To: Hoeflinger, Jay P
Cc: '[email protected]'; [email protected]; Neelakantam, NaveenX
Subject: RE: [Linux-ia64] determining read or write on a page fault

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Wed, 3 Apr 2002 08:18:45 -0800 , "Hoeflinger, Jay P"

<[email protected]> said:

Jay> We want to report success using the 2.4.18 kernel and the info Jay> sent to the segv handler on a page fault for our distributed Jay> virtual shared memory system on IA64.

Great! Glad to hear that.

Jay> We had to make one assumption, though, that wasn't covered in Jay> your mail (below).

Jay> The assumption was that if si_code=0, that the access was a Jay> "read". We had originally assumed it was a "write", but this Jay> caused some errors. When we changed to assuming "read", things Jay> worked. Is this assumption valid? When does this case occur? Jay> Our scan of the kernel source seemed to indicate that this case Jay> can't happen.

Hmmh, that's a bit odd. If si_code is zero, we can't know what triggered the segfault. It could have been a read, a write, a semaphore instruction, or something entirely different (e.g., user sending SIGSEGV via kill(2)). Now, for a distributed shared memory system, I'd have thought that you'd want to treat such unknown accesses as writes, because otherwise the fault might re-occur as soon as the faulting instruction is restarted (since the page still doesn't have write permission). For normal cases (non-error cases/silly user cases), I wouldn't have expected this to occur. Do you know where those SIGSEGVs with si_code=0 were coming from?

	--david
#13 lore raw
In reply to Hoeflinger, Jay P

It turns out that we have been running into a cc code generation bug. Changing the si_code = 0 case from "write" to "read" happened to make the bug go away.

We have rewritten our code to workaround the bug, and everything works as expected. Sorry for the false alarm.

Naveen Neelakantam

-----Original Message-----
From: Hoeflinger, Jay P
Sent: Wednesday, April 03, 2002 10:19 AM
To: '[email protected]'
Cc: [email protected]; Neelakantam, NaveenX
Subject: RE: [Linux-ia64] determining read or write on a page fault

We want to report success using the 2.4.18 kernel and the info sent to the segv handler on a page fault for our distributed virtual shared memory system on IA64. Thanks for your help. We had to make one assumption, though, that wasn't covered in your mail (below).

The assumption was that if si_code=0, that the access was a "read". We had originally assumed it was a "write", but this caused some errors. When we changed to assuming "read", things worked. Is this assumption valid? When does this case occur? Our scan of the kernel source seemed to indicate that this case can't happen.

Thanks

Jay Hoeflinger and Naveen Neelakantam

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Friday, February 22, 2002 7:25 PM
To: Hoeflinger, Jay P
Cc: [email protected]
Subject: RE: [Linux-ia64] determining read or write on a page fault

If you want to try with a new kernel, the attached patch should give you what you want. Specifically, if you get a SIGSEGV or a SIGBUS and si_code is non-zero, you can check si_flags. If it has the __ISR_VALID flag set, then the code in si_isr is valid. If si_isr is valid, you can check whether bit 34 (read exception) or bit 35 (non-access exception) is set. If so, you may assume that the signal was due to a load (or lfetch or some such). In all other cases, you'd have to play it safe and assume that you're dealing with a write access.

	--david

< patch deleted >

#14 lore raw
In reply to Hoeflinger, Jay P
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · NaveenX

Naveen> It turns out that we have been running into a cc code Naveen> generation bug. Changing the si_code = 0 case from "write" Naveen> to "read" happened to make the bug go away.

Naveen> We have rewritten our code to workaround the bug, and Naveen> everything works as expected. Sorry for the false alarm.

By "cc" do you mean gcc? If so, what version? Can you check whether the bug still occurs with the latest version of gcc (gcc3.0 or, better still, gcc3.1-prelease) or provide a test-case?

Thanks,

	--david
#15 lore raw
In reply to Hoeflinger, Jay P

Yes, I meant gcc (version 2.96 20000731). I've verified that the bug still exists in gcc3.0, but I haven't been able to create a testcase yet.

Naveen

-----Original Message-----
From: David Mosberger [mailto:[email protected]]
Sent: Monday, April 15, 2002 11:55 AM
To: Neelakantam, NaveenX
Cc: Hoeflinger, Jay P; '[email protected]'; '[email protected]'
Subject: RE: [Linux-ia64] determining read or write on a page fault

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Sun, 14 Apr 2002 15:08:54 -0700, "Neelakantam, NaveenX"

<[email protected]> said:

Naveen> It turns out that we have been running into a cc code Naveen> generation bug. Changing the si_code = 0 case from "write" Naveen> to "read" happened to make the bug go away.

Naveen> We have rewritten our code to workaround the bug, and Naveen> everything works as expected. Sorry for the false alarm.

By "cc" do you mean gcc? If so, what version? Can you check whether the bug still occurs with the latest version of gcc (gcc3.0 or, better still, gcc3.1-prelease) or provide a test-case?

Thanks,

	--david