Re: A question about PROT_NONE on ARM and ARM26

Jamie Lokier
2004-06-30T23:30:24Z

Russell King wrote:
> > Here's the potential improvement to current 32-bit ARM. It's
> > 4 instructions instead of 8 and one less load, in the common case:
> >
> > __get_user_4:
> > cmp r0, #TASK_SIZE-4
> > 4: ldrlet r1, [r0]
> > movle r0, #0
> > movle pc, lr
> > bic r1, sp, #0x1f00
> > bic r1, r1, #0x00ff
> > ldr r1, [r1, #TI_ADDR_LIMIT]
> > sub r1, r1, #4
> > cmp r0, r1
> > 14: ldrlet r1, [r0]
> > movle r0, #0
> > movle pc, lr
> > b __get_user_bad
>
> Ok, this could work, but there's one gotcha - TASK_SIZE-4 doesn't fit
> in an 8-bit rotated constants, so we need 2 extra instructions:
>
> __get_user_4:
> mov r1, #TASK_SIZE
> sub r1, r1, #4
> cmp r0, r1
> 4: ldrlet r1, [r0]
> movle r0, #0
> movle pc, lr
> ...

One more possibility:

cmp r0, #(TASK_SIZE - (1<<24))

I.e. just compare against the largest constant that can be
represented. For accesses to the last part of userspace, it's a
penalty of 4 instructions -- but it might work out to be a net gain.

Actually, since the shortest path is only three instructions in the
fast case, not counting control flow, it might be good to inline those
3 in uaccess.h, and change the "bl" to a conditonal "blhi" there.

> > Finally, I think I see a bug in current ARM. Shouldn't this use
> > ldrlet instead of ldrlst? Think about accesses to addresses
> > TASK_SIZE-4 and 0xfffffffc.
>
> LS = unsigned less than or same. LE = signed less than or equal. You
> need the unsigned compare because addresses are unsigned.

Ah. I was guessing the mnemonic.

That's because of the way "ge" is used on ARM26 in places, which
therefore look buggy or subtly clever:

ldr r1, [r1, #TI_ADDR_LIMIT]
sub r1, r1, #4
cmp r0, r1
bge __get_user_bad
cmp r0, #0x02000000
4: ldrlst r1, [r0]
ldrge r1, [r0]

"ge" is a signed comparison, and unsigned is needed here, unless I
missed something subtle. So "bge" and "ldrge" should be "bhi" and "ldrhi".

Thanks,
-- Jamie