Revamp exception handling in the kernel
RFC 1/1 Revamp exception handling in the kernel
Currently, palinux handles exceptions differently from other architectures in the kernel. On most other architectures, an exception to a read/store that has an associated exception table entry in the kernel is handled by code in a fixup section, which is responsible for setting the proper return values, etc.
On pa, we currently have an interesting scheme that associates a "skip" value with each exception entry. The bottom two bits of the skip value indicates whether r8,r9 should be set to -EFAULT,0 during a fault, and the top bits indicate a relative adjustment that should be applied to the iaoq to handle the fault.
The patch below, based on my discussions with jejb, changes this behaviour so that it more closely matches what happens on other architectures (but with a twist...): the exception table entries now contain an *absolute* address to branch to for the fixup [1]. The fixups are placed in a separate fixup section (this simplifies a bit of code in unaligned.c too). The fixup code loads up whatever values are required by the caller, and typically branches back to the original code at a correct location to continue.
This frees up the bottom two bits for other purposes -- currently there is no way to pass the faulting address and instruction back to an exception table handler. The proposal is to reuse the bottom 2 bits to indicate whether the faulting address/insn should be passed back to the handler in r8/r9. (this will be used by the optimized pa copy routines, for example)
One downside of this approach is that the extra fixup sections take up more space, so the end kernel is bigger. In my test on 64-bit, the kernel size increases by ~2%.
The patch below has been tested against 2.6.8.1-pa11 on 64-bit-SMP, and compile tested on 32-bit-UP. I don't have a 32-bit machine to test on atm, so test reports are most welcome [2]. I've applied the manual stubs trick that jejb mentioned earlier, but only for 64-bit, since the 32-bit linker is able to generate those stubs automatically when needed.
Comments?
randolph
[1] The change to using absolute jumps is because gas doesn't want to let us take the difference of labels in two different sections (viz. .text vs .fixup). jejb and I are not able to come up with a case where using relative jumps is required.
[2] Since this changes the *exception* path, simply booting a kernel or building things will not exercise the new code. You need to do something that will trigger a load/store fault on userspace in the kernel. If I were Carlos I would have attached a nice testsuite to this patch, but alas I've only done some manual testing on a few cases.... there's a debug printk in this patch which will print something like:
"applying fixup for 0x10281ae4, fixup at 0x103ca614"
if you see that, then you are exercising the new code.
Index: arch/parisc/kernel/syscall.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/syscall.S,v retrieving revision 1.14
parisc/kernel/syscall.S +21 -9
@@ -29,6 +29,19 @@ #else .level 1.1 #endif + +#ifndef __LP64__ + .macro fixup_branch,lbl + b \lbl + .endm +#else + .macro fixup_branch,lbl + ldil L%\lbl, %r1 + ldo R%\lbl(%r1), %r1 + bv,n %r0(%r1) + .endm +#endif + .text .import syscall_exit,code
@@ -575,10 +588,8 @@ cas_action: /* Return to userspace, set no error */ b lws_exit copy %r0, %r21 - nop /* Add some visual space in objdump */ - nop - nop - nop + + .section .fixup,"ax" 3: /* Error occured on load or store */ #ifdef CONFIG_SMP
@@ -588,12 +599,13 @@ cas_action: stw %r0, 4(%sr2,%r20) # endif #endif - b lws_exit + fixup_branch lws_exit ldo -EFAULT(%r0),%r21 /* set errno */ nop nop nop nop + .previous /* Two exception table entries, one for the load, the other for the store. Either return -EFAULT */
@@ -601,10 +613,10 @@ cas_action: #ifdef __LP64__ /* Pad the address calculation */ .word 0,(2b - linux_gateway_page) - .dword (3b - 2b) + .dword 3b #else .word 2b - linux_gateway_page - .word (3b - 2b) + .word 3b #endif .previous
@@ -612,10 +624,10 @@ cas_action: #ifdef __LP64__ /* Pad the address calculation */ .word 0,(1b - linux_gateway_page) - .dword (3b - 1b) + .dword 3b #else .word 1b - linux_gateway_page - .word (3b - 1b) + .word 3b #endif .previous
Index: arch/parisc/kernel/unaligned.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/unaligned.c,v retrieving revision 1.8
parisc/kernel/unaligned.c +103 -71
241 lines not on this page · raw message
Index: arch/parisc/lib/lusercopy.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/lib/lusercopy.S,v retrieving revision 1.3
parisc/lib/lusercopy.S +52 -28
150 lines not on this page · raw message
Index: arch/parisc/mm/fault.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/mm/fault.c,v retrieving revision 1.1
parisc/mm/fault.c +7 -5
@@ -235,12 +235,14 @@ no_context:if (fix) { -if (fix->skip &1 ) - regs->gr[8 ] = -EFAULT ; -if (fix->skip &2 ) - regs->gr[9 ] =0 ; +printk ("applying fixup for 0x%lx, fixup at 0x%lx\n" , regs->iaoq[0 ], fix->fixup & ~3 ); - regs->iaoq[0 ] += ((fix->skip) & ~3 ); +if (fix->fixup &1 ) + regs->gr[8 ] = regs->iir; +if (fix->fixup &2 ) + regs->gr[9 ] = regs->ior; + + regs->iaoq[0 ] = ((fix->fixup) & ~3 );/* * NOTE: In some cases the faulting instruction
Index: include/asm-parisc/uaccess.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/uaccess.h,v retrieving revision 1.13
asm-parisc/uaccess.h +87 -42
210 lines not on this page · raw message
Signature · 7 lines
Randolph Chung Debian GNU/Linux Developer, hppa/ia64 ports http://www.tausq.org/ _______________________________________________ parisc-linux mailing list [email protected] http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 4 lines
[1] The change to using absolute jumps is because gas doesn't want to let us take the difference of labels in two different sections (viz. .text vs .fixup). jejb and I are not able to come up with a case where using relative jumps is required.
Right. However, there is a way to do 32/64 bit pc-relative offsets. The table entries need to look like "L$1+(.+8-L$0)-$PIC_pcrel$0". GAS needs to be reasonably new to support this.
Dave
Signature · 6 lines
J. David Anglin [email protected] National Research Council of Canada (613) 990-0752 (FAX: 952-6602) _______________________________________________ parisc-linux mailing list [email protected] http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 8 lines · John David Anglin
Quoted 4 lines
[1] The change to using absolute jumps is because gas doesn't want to let us take the difference of labels in two different sections (viz. .text vs .fixup). jejb and I are not able to come up with a case where using relative jumps is required.
Right. However, there is a way to do 32/64 bit pc-relative offsets. The table entries need to look like "L$1+(.+8-L$0)-$PIC_pcrel$0". GAS needs to be reasonably new to support this.
Interesting.
I thought I needed relative fixups, then I realized I was wrong.
I use exception fixups for LWS on the gateway page, but I can just fudge the exception entries differently. No big problem since I have to do a fixed relocation on them anyway.
c.
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 8 lines
The patch below, based on my discussions with jejb, changes this behaviour so that it more closely matches what happens on other architectures (but with a twist...): the exception table entries now contain an *absolute* address to branch to for the fixup [1]. The fixups are placed in a separate fixup section (this simplifies a bit of code in
unaligned.ctoo). The fixup code loads up whatever values are required by the caller, and typically branches back to the original code at a correct location to continue.
I'm looking through the module loading code and worrying about how absolute fixups works when a module needs a fixup?
Quoted 6 lines
This frees up the bottom two bits for other purposes -- currently there is no way to pass the faulting address and instruction back to an exception table handler. The proposal is to reuse the bottom 2 bits to indicate whether the faulting address/insn should be passed back to the handler in r8/r9. (this will be used by the optimized pa copy routines, for example)
I think this is a brilliant proposal. I found the use of r8/r9 a bit washy and rather useless in the current implementation.
Quoted 3 lines
One downside of this approach is that the extra fixup sections take up more space, so the end kernel is bigger. In my test on 64-bit, the kernel size increases by ~2%.
What is that converted to bytes?
Quoted 7 lines
The patch below has been tested against 2.6.8.1-pa11 on 64-bit-SMP, and compile tested on 32-bit-UP. I don't have a 32-bit machine to test on atm, so test reports are most welcome [2]. I've applied the manual stubs trick that jejb mentioned earlier, but only for 64-bit, since the 32-bit linker is able to generate those stubs automatically when needed.
Comments?
How are we handling module fixups with absolute fixup addresses?
Is there ever a case where you want only the faulting instruction and not the faulting address aswell? This might be a case for saving a flag, if you are going to write to r9 you might aswell write two words, anyway? The code has already locked r8/r9 into variables and gcc won't do a better job for you.
0x2 = 1 then Write r8/r9 values (slow path)0x2 = 0 then do nothing (fast path)
Then 0x1 is free to be used for something magical.
c.
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 2 lines · Carlos O'Donell
I'm looking through the module loading code and worrying about how absolute fixups works when a module needs a fixup?
It should work identically to non-module code ... what specifically is worrying you?
Quoted 1 line
How are we handling module fixups with absolute fixup addresses?
The same way we do in the regular kernel ... jump to the absolute address.
James
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 5 lines
Quoted 2 lines
I'm looking through the module loading code and worrying about how absolute fixups works when a module needs a fixup?
It should work identically to non-module code ... what specifically is worrying you?
Are relocations generated against the exception table entries?
Quoted 2 lines
The same way we do in the regular kernel ... jump to the absolute address.
If relocations are generated against extable entries then all should be okay. The address will be fixed by the loader and everything is fine.
That was my only worry, Randolph didn't seem to address testing a failed copy_from_user through a module extable.
My other question about freeing a flag still stands though.
c.
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 1 line · Carlos O'Donell
Are relocations generated against the exception table entries?
Yes. A module is just a normal .o file with a few extra sections. It contains all the relocations a .o file usually contains.
Quoted 10 lines
Quoted 2 lines
The same way we do in the regular kernel ... jump to the absolute address.
If relocations are generated against extable entries then all should be okay. The address will be fixed by the loader and everything is fine.
That was my only worry, Randolph didn't seem to address testing a failed
copy_from_userthrough a module extable.My other question about freeing a flag still stands though.
I'll let Randolph answer that ... I find thinks like this are sticky; once you touch them you can never get them off your hands...
James
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 5 lines
Quoted 3 lines
One downside of this approach is that the extra fixup sections take up more space, so the end kernel is bigger. In my test on 64-bit, the kernel size increases by ~2%.
What is that converted to bytes?
about 100k for 64-bit. should be significantly less for 32-bit.
Quoted 5 lines
Is there ever a case where you want only the faulting instruction and not the faulting address aswell? This might be a case for saving a flag, if you are going to write to r9 you might aswell write two words, anyway? The code has already locked r8/r9 into variables and gcc won't do a better job for you.
actually a nice effect of this patch is that you don't need to lock down r8 and r9 anymore for the get_user/put_user cases. Potentially any register can be used to store the error and result values.
i need to do some experiments to verify this, but after thinking about it more last night, it seems to me that we don't even need to put the isr/ior into registers in the fault handler. the fixup code could potentially just look at current->thread.regs.isr/ior directly.
Quoted 4 lines
0x2= 1 then Write r8/r9 values (slow path)0x2= 0 then do nothing (fast path)Then
0x1is free to be used for something magical.
sure, that works too.
randolph
Signature · 7 lines
Randolph Chung Debian GNU/Linux Developer, hppa/ia64 ports http://www.tausq.org/ _______________________________________________ parisc-linux mailing list [email protected] http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 3 lines
Quoted 1 line
What is that converted to bytes?
about 100k for 64-bit. should be significantly less for 32-bit.
That's quite a bit, but it does make the infrastructure more flexible. I don't think anyone is going to be building embedded PA systems, but lets not bloat.
Quoted 9 lines
Quoted 5 lines
Is there ever a case where you want only the faulting instruction and not the faulting address aswell? This might be a case for saving a flag, if you are going to write to r9 you might aswell write two words, anyway? The code has already locked r8/r9 into variables and gcc won't do a better job for you.
actually a nice effect of this patch is that you don't need to lock down r8 and r9 anymore for the get_user/put_user cases. Potentially any register can be used to store the error and result values.
I don't see how the fixup code knows which registers to use?
Quoted 4 lines
i need to do some experiments to verify this, but after thinking about it more last night, it seems to me that we don't even need to put the isr/ior into registers in the fault handler. the fixup code could potentially just look at current->thread.regs.isr/ior directly.
Yes, that's very true, just fillin those values during the fixup phase. Then you don't need to use r8/r9 and the flags just become "Yes I care, please deposit the value" or "No I don't care."
Quoted 6 lines
Quoted 4 lines
0x2= 1 then Write r8/r9 values (slow path)0x2= 0 then do nothing (fast path)Then
0x1is free to be used for something magical.sure, that works too.
I'm not sure what we would use the flag for, but it's nice to have it there. Perhaps we may in the future wish to have absolute and relative fixups based on the flag? This would reduce the kernel size bloat and produce faster code again. Technically only the pa_memcpy code is the only one that would have to enable "absolute" fixups?
c.
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 3 lines
That's quite a bit, but it does make the infrastructure more flexible. I don't think anyone is going to be building embedded PA systems, but lets not bloat.
yes, that's why i brought it up :)
Quoted 5 lines
Quoted 3 lines
actually a nice effect of this patch is that you don't need to lock down r8 and r9 anymore for the get_user/put_user cases. Potentially any register can be used to store the error and result values.
I don't see how the fixup code knows which registers to use?
Consider:
#define __get_user_asm(ldx,ptr) \
__asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n" \
"2:\n" \
"\t.section .fixup,\"ax\"\n" \
"3:\tldi -14, %1\n" \
"\tcopy %%r0, %0\n" \
FIXUP_BRANCH(2b) \
"\t.previous" \
"\t.section __ex_table,\"aw\"\n" \
"\t.word\t1b,3b\n" \
"\t.previous" \
: "=r"(__gu_val), "=r"(__gu_err) \
: "r"(ptr), "1"(__gu_err));By the time the fixup is called, we are back into user context. the ldi/copy will write into whatever registers store __gu_val, __gu_err, and then branch back to "2:", so essentially this code is self-contained. There is no real requirements that __gu_val/__gu_err be in any special registers.
In the original code, we have to write to r8/r9 inside interruption context, and have the values survive back to user context.
Quoted 8 lines
Quoted 4 lines
i need to do some experiments to verify this, but after thinking about it more last night, it seems to me that we don't even need to put the isr/ior into registers in the fault handler. the fixup code could potentially just look at current->thread.regs.isr/ior directly.
Yes, that's very true, just fillin those values during the fixup phase. Then you don't need to use r8/r9 and the flags just become "Yes I care, please deposit the value" or "No I don't care."
nono, you don't fill them up in the fixup phase.
when you have a fault, we already store the ior/isr into the pt_regs structure. so as long as we are not clobbering those in the interruption exit path, it will still be accessible in the fixup code.
Quoted 5 lines
I'm not sure what we would use the flag for, but it's nice to have it there. Perhaps we may in the future wish to have absolute and relative fixups based on the flag? This would reduce the kernel size bloat and produce faster code again. Technically only the
pa_memcpycode is the only one that would have to enable "absolute" fixups?
why do you think absolute fixups take more space? in fact, absolute fixup is what might allow us to save space.
the bit that is taking up more space is that the logic that stores -EFAULT/0 is now duplicated for each get_user/put_user call. For 64-bit kernels, that's 5 insns per call. In the original implementation, this logic is centralized in the fault handling code.
possibly, we can create a centralized fixup routine in arch/parisc/lib/fixup.S that looks like:
.section .fixup, "ax"fixup_load_skip_1:
ldi -14, %r8
copy %r0, %r9
mfctl %cr30, %r1
LDREG 0(%r1), %r1
LDREG TASK_PT_IOR(%r1), %r1
ldo 4(%r1), %r1
bv,n %r0(%r1)and __get_user_asm() will become
#define __get_user_asm(ldx,ptr) \
__asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n" \
"2:\n" \
"\t.section __ex_table,\"aw\"\n" \
"\t.word\t1b,fixup_load_skip_1\n" \
"\t.previous" \
: "=r"(__gu_val), "=r"(__gu_err) \
: "r"(ptr), "1"(__gu_err));similarly we will have fixup_store_skip_1, and for 32-bit we also need fixup_load_skip_2 and fixup_store_skip_2 for the 64-bit get_user/put_user calls.
this reintroduces the requirement that __gu_val and __gu_err be in fixed registers, but the fixup regions don't need to be duplicated, so the kernel size should become smaller again.
thoughts?
randolph
Signature · 7 lines
Randolph Chung Debian GNU/Linux Developer, hppa/ia64 ports http://www.tausq.org/ _______________________________________________ parisc-linux mailing list [email protected] http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Randolph,
Quoted 3 lines
when you have a fault, we already store the ior/isr into the
pt_regsstructure. so as long as we are not clobbering those in the interruption exit path, it will still be accessible in the fixup code.
I worry that the fixup code may trigger another interruption and clobber those values before it can read them? Any interruption will resave ior/isr. Perhaps storing them into r8/r9 is still best.
Quoted 24 lines
possibly, we can create a centralized fixup routine in
arch/parisc/lib/fixup.Sthat looks like:.section .fixup, "ax"
fixup_load_skip_1:ldi -14, %r8 copy %r0, %r9 mfctl %cr30, %r1 LDREG 0(%r1), %r1 LDREG TASK_PT_IOR(%r1), %r1 ldo 4(%r1), %r1 bv,n %r0(%r1)and
__get_user_asm()will become#define __get_user_asm(ldx,ptr) \ __asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n" \ "2:\n" \ "\t.section __ex_table,\"aw\"\n" \ "\t.word\t1b,fixup_load_skip_1\n" \ "\t.previous" \ : "=r"(__gu_val), "=r"(__gu_err) \ : "r"(ptr), "1"(__gu_err));
Quoted 3 lines
similarly we will have
fixup_store_skip_1, and for 32-bit we also needfixup_load_skip_2andfixup_store_skip_2for the 64-bit get_user/put_user calls.
That would be a brilliant space saver. I take it back, I hand't thought about interrupting to a generic fixup function for all the __get_user_asm uses.
Quoted 3 lines
this reintroduces the requirement that
__gu_valand__gu_errbe in fixed registers, but the fixup regions don't need to be duplicated, so the kernel size should become smaller again.
Implementation?
a. Single generic fixup for all the asm macros (reduce kernel size).
- Fixes previous quibble that absolute addresses made the kernel bigger because asm macros had more insns.
b. Absoulte fixup addresses (allows fixup to be anywhere). c. Use only one flag in the fixup address to indicate wether
r8/r9 should be written to with ior/iir or not. Leaving a spare flag for future uses.
Pro:
o Kernel size is smaller.
- Bonus!
o fixup can be located almost anywhere (absolute address).
- Bonus!
o Custom code can examine r8/r9 to determine more accurately the faulting situation.
- Bonus!
Con:
o Generic slow path is a couple more insns slower ;)
- Regression, no worries.
o Generic fixup always locks r8/r9 into gu_err and gu_val
- Same as always.
c.
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Version 2 of the patch. Changes from the previous version:
- Uses centralized exception handling for get_user/put_user
- Uses per-cpu variables to store the fault ip, fault space and fault address (not controlled by a flag)
- 64-bit get_user/put_user for 32-bit kernels is a bit broken in the old code. this contains a fix for that as well.
Tested against 2.6.8.1-pa11 for 64-UP and 64-SMP
jejb asked me why we don't do the fixup in C code. It seems to me that in order to do that, we will need to mark all the caller-saved registers as clobbered by get_user/put_user. That may cause a large amount of register spills across those calls, even for non-faulting cases. But the alternative (as implemented below) is some rather nasty-looking asm code in the fixup handler. A third alternative might be for the fixup handler to create a stack frame and save/restore caller-saved registers across a call to a C-code handler. seems like a lot of work....
Thoughts?
randolph
Index: arch/parisc/kernel/asm-offsets.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/asm-offsets.c,v retrieving revision 1.9
parisc/kernel/asm-offsets.c +4 -0
@@ -38,6 +38,7 @@#include <asm/processor.h> #include <asm/hardirq.h> #include <asm/pdc.h> +#include <asm/uaccess.h> #define DEFINE (sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -291,5 +292,8 @@ int main(void)DEFINE (ASM_PT_INITIAL ,PT_INITIAL );DEFINE (ASM_PAGE_SIZE ,PAGE_SIZE );BLANK (); +DEFINE (EXCDATA_IP , offsetof(struct exception_data , fault_ip)); +DEFINE (EXCDATA_SPACE , offsetof(struct exception_data , fault_space)); +DEFINE (EXCDATA_ADDR , offsetof(struct exception_data , fault_addr));return 0 ; }
Index: arch/parisc/kernel/syscall.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/syscall.S,v retrieving revision 1.14
parisc/kernel/syscall.S +21 -9
@@ -29,6 +29,19 @@ #else .level 1.1 #endif + +#ifndef __LP64__ + .macro fixup_branch,lbl + b \lbl + .endm +#else + .macro fixup_branch,lbl + ldil L%\lbl, %r1 + ldo R%\lbl(%r1), %r1 + bv,n %r0(%r1) + .endm +#endif + .text .import syscall_exit,code
@@ -575,10 +588,8 @@ cas_action: /* Return to userspace, set no error */ b lws_exit copy %r0, %r21 - nop /* Add some visual space in objdump */ - nop - nop - nop + + .section .fixup,"ax" 3: /* Error occured on load or store */ #ifdef CONFIG_SMP
@@ -588,12 +599,13 @@ cas_action: stw %r0, 4(%sr2,%r20) # endif #endif - b lws_exit + fixup_branch lws_exit ldo -EFAULT(%r0),%r21 /* set errno */ nop nop nop nop + .previous /* Two exception table entries, one for the load, the other for the store. Either return -EFAULT */
@@ -601,10 +613,10 @@ cas_action: #ifdef __LP64__ /* Pad the address calculation */ .word 0,(2b - linux_gateway_page) - .dword (3b - 2b) + .dword 3b #else .word 2b - linux_gateway_page - .word (3b - 2b) + .word 3b #endif .previous
@@ -612,10 +624,10 @@ cas_action: #ifdef __LP64__ /* Pad the address calculation */ .word 0,(1b - linux_gateway_page) - .dword (3b - 1b) + .dword 3b #else .word 1b - linux_gateway_page - .word (3b - 1b) + .word 3b #endif .previous
Index: arch/parisc/kernel/unaligned.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/unaligned.c,v retrieving revision 1.8
parisc/kernel/unaligned.c +109 -71
255 lines not on this page · raw message
Index: arch/parisc/lib/Makefile
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/lib/Makefile,v retrieving revision 1.2
parisc/lib/Makefile +1 -1
@@ -2,6 +2,6 @@ # Makefile for parisc-specific library files # -lib-y := lusercopy.o bitops.o checksum.o io.o memset.o +lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o lib-$(CONFIG_SMP) += debuglocks.o
Index: arch/parisc/lib/fixup.S
===================================================================
RCS file: arch/parisc/lib/fixup.S
parisc/lib/fixup.S new file +84 -0
84 lines not on this page · raw message
Index: arch/parisc/lib/lusercopy.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/lib/lusercopy.S,v retrieving revision 1.3
parisc/lib/lusercopy.S +52 -28
150 lines not on this page · raw message
Index: arch/parisc/mm/fault.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/mm/fault.c,v retrieving revision 1.1
parisc/mm/fault.c +11 -5
@@ -36,6 +36,9 @@#define BITSSET 0x1c0/* for identifying LDCW */ + +DEFINE_PER_CPU(struct exception_data, exception_data); +/* * parisc_acctyp(unsigned int inst) -- * Given a PA-RISC memory access instruction, determine if the
@@ -234,13 +237,16 @@ no_context: fix =search_exception_tables (regs->iaoq[0 ]);if (fix) { +struct exception_data *d; + +printk ("applying fixup for 0x%lx, fixup at 0x%lx\n" , regs->iaoq[0 ], fix->fixup & ~3 ); -if (fix->skip &1 ) - regs->gr[8 ] = -EFAULT ; -if (fix->skip &2 ) - regs->gr[9 ] =0 ; + d = &__get_cpu_var (exception_data); + d->fault_ip = regs->iaoq[0 ]; + d->fault_space = regs->isr; + d->fault_addr = regs->ior; - regs->iaoq[0 ] += ((fix->skip) & ~3 ); + regs->iaoq[0 ] = ((fix->fixup) & ~3 );/* * NOTE: In some cases the faulting instruction
Index: include/asm-parisc/uaccess.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/uaccess.h,v retrieving revision 1.13
asm-parisc/uaccess.h +60 -77
203 lines not on this page · raw message
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Version 2a of the patch. Changes from the previous version:
- Fixed the comment in uaccess.h, added some more comments to fixup.S
- Added missing r1 clobbers
- addil/ldd should be relative to r27, not r1
i found out this is a somewhat effective way of testing this patch:
- run "make vmlinux" (or make -j4 vmlinux) in one window
- run "while true; do ./wtest; sleep 30; done" in another window
wtest is compiled from:
-------------------8< cut here 8<-------------------- #include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char **argv)
{
char *buf = (char *)1;
int ret;
ret = write(fileno(stdout), buf, 10);
printf("write returned ret = %d, errno = %d\n", ret, errno);
return 0;
}-------------------8< cut here 8<--------------------
patch:
Index: arch/parisc/kernel/asm-offsets.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/asm-offsets.c,v retrieving revision 1.9
parisc/kernel/asm-offsets.c +4 -0
@@ -38,6 +38,7 @@#include <asm/processor.h> #include <asm/hardirq.h> #include <asm/pdc.h> +#include <asm/uaccess.h> #define DEFINE (sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -291,5 +292,8 @@ int main(void)DEFINE (ASM_PT_INITIAL ,PT_INITIAL );DEFINE (ASM_PAGE_SIZE ,PAGE_SIZE );BLANK (); +DEFINE (EXCDATA_IP , offsetof(struct exception_data , fault_ip)); +DEFINE (EXCDATA_SPACE , offsetof(struct exception_data , fault_space)); +DEFINE (EXCDATA_ADDR , offsetof(struct exception_data , fault_addr));return 0 ; }
Index: arch/parisc/kernel/syscall.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/syscall.S,v retrieving revision 1.14
parisc/kernel/syscall.S +21 -9
@@ -29,6 +29,19 @@ #else .level 1.1 #endif + +#ifndef __LP64__ + .macro fixup_branch,lbl + b \lbl + .endm +#else + .macro fixup_branch,lbl + ldil L%\lbl, %r1 + ldo R%\lbl(%r1), %r1 + bv,n %r0(%r1) + .endm +#endif + .text .import syscall_exit,code
@@ -575,10 +588,8 @@ cas_action: /* Return to userspace, set no error */ b lws_exit copy %r0, %r21 - nop /* Add some visual space in objdump */ - nop - nop - nop + + .section .fixup,"ax" 3: /* Error occured on load or store */ #ifdef CONFIG_SMP
@@ -588,12 +599,13 @@ cas_action: stw %r0, 4(%sr2,%r20) # endif #endif - b lws_exit + fixup_branch lws_exit ldo -EFAULT(%r0),%r21 /* set errno */ nop nop nop nop + .previous /* Two exception table entries, one for the load, the other for the store. Either return -EFAULT */
@@ -601,10 +613,10 @@ cas_action: #ifdef __LP64__ /* Pad the address calculation */ .word 0,(2b - linux_gateway_page) - .dword (3b - 2b) + .dword 3b #else .word 2b - linux_gateway_page - .word (3b - 2b) + .word 3b #endif .previous
@@ -612,10 +624,10 @@ cas_action: #ifdef __LP64__ /* Pad the address calculation */ .word 0,(1b - linux_gateway_page) - .dword (3b - 1b) + .dword 3b #else .word 1b - linux_gateway_page - .word (3b - 1b) + .word 3b #endif .previous
Index: arch/parisc/kernel/unaligned.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/unaligned.c,v retrieving revision 1.8
parisc/kernel/unaligned.c +109 -71
255 lines not on this page · raw message
Index: arch/parisc/lib/Makefile
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/lib/Makefile,v retrieving revision 1.2
parisc/lib/Makefile +1 -1
@@ -2,6 +2,6 @@ # Makefile for parisc-specific library files # -lib-y := lusercopy.o bitops.o checksum.o io.o memset.o +lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o lib-$(CONFIG_SMP) += debuglocks.o
Index: arch/parisc/lib/fixup.S
===================================================================
RCS file: arch/parisc/lib/fixup.S
parisc/lib/fixup.S new file +89 -0
89 lines not on this page · raw message
Index: arch/parisc/lib/lusercopy.S
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/lib/lusercopy.S,v retrieving revision 1.3
parisc/lib/lusercopy.S +52 -28
150 lines not on this page · raw message
Index: arch/parisc/mm/fault.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/mm/fault.c,v retrieving revision 1.1
parisc/mm/fault.c +11 -5
@@ -36,6 +36,9 @@#define BITSSET 0x1c0/* for identifying LDCW */ + +DEFINE_PER_CPU(struct exception_data, exception_data); +/* * parisc_acctyp(unsigned int inst) -- * Given a PA-RISC memory access instruction, determine if the
@@ -234,13 +237,16 @@ no_context: fix =search_exception_tables (regs->iaoq[0 ]);if (fix) { +struct exception_data *d; + +printk ("applying fixup for 0x%lx, fixup at 0x%lx\n" , regs->iaoq[0 ], fix->fixup & ~3 ); -if (fix->skip &1 ) - regs->gr[8 ] = -EFAULT ; -if (fix->skip &2 ) - regs->gr[9 ] =0 ; + d = &__get_cpu_var (exception_data); + d->fault_ip = regs->iaoq[0 ]; + d->fault_space = regs->isr; + d->fault_addr = regs->ior; - regs->iaoq[0 ] += ((fix->skip) & ~3 ); + regs->iaoq[0 ] = ((fix->fixup) & ~3 );/* * NOTE: In some cases the faulting instruction
Index: include/asm-parisc/uaccess.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/uaccess.h,v retrieving revision 1.13
asm-parisc/uaccess.h +78 -85
224 lines not on this page · raw message
randolph
Signature · 7 lines
Randolph Chung Debian GNU/Linux Developer, hppa/ia64 ports http://www.tausq.org/ _______________________________________________ parisc-linux mailing list [email protected] http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
Quoted 28 lines · Randolph Chung
Version 2a of the patch. Changes from the previous version:
- Fixed the comment in
uaccess.h, added some more comments tofixup.S
- Added missing r1 clobbers
- addil/ldd should be relative to r27, not r1i found out this is a somewhat effective way of testing this patch:
- run "make vmlinux" (or make -j4 vmlinux) in one window
- run "while true; do ./wtest; sleep 30; done" in another windowwtest is compiled from:
-------------------8< cut here 8<-------------------- #include <stdio.h>
#include <unistd.h>
#include <errno.h>int
main(int argc, char **argv){ char *buf = (char *)1; int ret; ret = write(fileno(stdout), buf, 10); printf("write returned ret = %d, errno = %d\n", ret, errno); return 0; }
Quoted 2 lines
-------------------8< cut here 8<--------------------
[...]
mmm, just running wtest and:
applying fixup for 0x10100350, fixup at 0x1038e1d8
Backtrace: [<1024fee0>] opost_block+0x58/0x1f8 [<10252d84>] write_chan+0x204/0x2a8 [<1024c02c>] tty_write+0x260/0x32c [<1017d6b0>] vfs_write+0x100/0x148 [<1017d7fc>] sys_write+0x5c/0xa8 [<10110178>] syscall_exit+0x0/0x14
Kernel Fault: Code=26 regs=2a9fc3c0 (Addr=00000001)
YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI
PSW: 00000000000001101111111100001111 Not tainted
r00-03 00000000 00000aa0 1024fee0 0000000a r04-07 2cb89000 00000001 2cb89000 2cc95320 r08-11 00000000 00000001 00000000 2cb89948 r12-15 00000001 00000000 000aa000 000eae68 r16-19 000eaf08 000eab48 00000000 00000000 r20-23 30000001 00000fff 00000001 00000000 r24-27 0000000a 00000001 2a9fc312 103ef010 r28-31 00000fff 00000000 2a9fc3c0 102540d8 sr0-3 00000000 00000aa0 00000000 00000aa0 sr4-7 00000000 00000000 00000000 00000000
IASQ: 00000000 00000000 IAOQ: 10100320 10100324
IIR: 0f221021 ISR: 00000000 IOR: 00000001
CPU: 0 CR30: 2a9fc000 CR31: 10454000
ORIG_R28: 00000000
IAOQ[0]: $lctu_loop+0x0/0xc
IAOQ[1]: $lctu_loop+0x4/0xc
RP(r2): opost_block+0x58/0x1f8
Kernel panic - not syncing: Kernel Fault
Is panic awaited?
TIA,
Joel
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux