[lkml]   [1996]   [Oct]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
SubjectRe: Linux-2.1.4
> another option is to trick gcc into producing the proper symbol entries
> around the exception-prone code. We have to generate two symbols:
> symbol_1: mov src, target_that_might_fault
> symbol_2: exception_handling_logic
> Thus the exception handler only has to read the EIP value of symbol_2 out
> of a table indexed by symbol_1 [=exception EIP].

This general idea sounds very promising. And it doesn't need a custom
program to implement either. Consider the following for the Alpha:

#define get_user_64(x,addr) \
({ \
long __err; \
__asm__("clr %1\n" \
"1: ldq %0, %2\n" \
".section __ex_table,\"aw\"\n\t" \
".quad 1b\n" \
".text" \
: "=r"(x), "=r"(__err) \
: "m"(*(addr))); \
__err; \

Notice that we are collecting the address of the instruction that is
allowed to fault in section __ex_table. There is an ld feature (at
least as of binutils 2.7) that, for each section whose entire name
is a valid C symbol, generates the two symbols __start_<section> and
__stop_<section>. Additionally, due to the way the data is generated
and sections assembled, we know that the addresses will be sorted by
increasing address.

Thus we can get the extent of the table and do a binary search for our
faulting address, the register in which to store -EFAULT from
*(pc - 4) & 0x1f, and the return address is the next instruction.

That simple table and two instruction idea should work in all cases
for any machine that can direcly load/store all data sizes.

For the Alpha, we need more to handle sub-word loads/stores efficiently.
For get_user_8 the insn sequence is

clr err
1: ldq_u val, addr
extbl val, addr, val

and for put_user_8 the sequence is

clr err
1: ldq_u tmp, addr
insbl val, addr, tmp2
mskbl tmp, addr, tmp
or tmp, tmp2, tmp
2: stq_u tmp, addr

Now, here we have three options. First, we could add knowledge about
how to decode these fragments into the exception handler so that it
knows how to handle each case via the single address entry. Second,
we could put the 1's addresses in separate tables and build only the
knowledge of the exact displacements into the exception handler.
Finally, we could use a table format such as:

.quad 1b
.byte 3b-1b, 2b-1b, 2b-3b, <errreg>

At this point I'm in favour of the first option, as kernel space should
be put at a premium. Continuing to think along those lines, it'd be
nice if we could use .gprel32 instead of .quad. This, I think, requires
a tiny compiler patch to add a bit to force the surrounding function to
load its gp so it'd be available for the exception handler.

This covers the single load/store case, what about the block routines
such as clear_user? They certainly will still want to be able to
bail out of the entire operation directly.

I'd suggest that this be done by exchanging the exception count + known
register for a single abort address, since the nested exceptions we could
have gotten with exception() ... end_exception() are no longer possible.

Oh yes, modules. We'd need to make modules register their tables on
startup so that we can search those as well.

Comments? No rush on any of this really; we have lots of things to do
in the meantime.


 \ /
  Last update: 2005-03-22 13:37    [W:0.038 / U:0.900 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site