[RFC PATCH v3] ARM: Introduce patching of phys_to_virt and vice versa
Nicolas Pitre
nico at fluxnic.net
Wed Nov 10 15:23:50 EST 2010
On Mon, 8 Nov 2010, Russell King - ARM Linux wrote:
> noting that:
>
> add rd, rn, #PAGE_OFFSET - PHYS_OFFSET
> sub rd, rn, #PHYS_OFFSET - PAGE_OFFSET
>
> are equivalent.
>
> We can do better than this - just make sure that all virt_to_phys() are an
> add instruction, and all phys_to_virt() are a sub struction. Then we only
> need to fixup the constant. IOW, virt_to_phys() is:
>
> add rd, rn, #PHYS_OFFSET - PAGE_OFFSET
>
> and phys_to_virt() is:
>
> sub rd, rn, #PHYS_OFFSET - PAGE_OFFSET
Does this work even if PHYS_OFFSET - PAGE_OFFSET goes negative?
Shouldn't we need to switch the encoding of an add into a sub and vice
versa with a positive immediate value in that case? (I don't have the
instruction encoding info handy at the moment).
On Wed, 10 Nov 2010, Russell King - ARM Linux wrote:
> Here's something which uses the above ideas (untested). I think this is
> something we can (and should) do unconditionally for the !XIP cases.
What do you mean by "unconditionally"?
> We also need to fixup modules in a similar manner, so we want to place
> the __fixup_pv_table function in the .text, and give it a wrapper
> along the lines of:
[...]
Modules... of course. I hadn't thought about them.
> Second version - let's get _all_ v:p translations, not just virt_to_phys
> and phys_to_virt (iow, __phys_to_virt/__virt_to_phys/__pa/__va) which will
> include all the page table manipulations, default bus<->virt translations.
> This results in a _much_ bigger fixup table.
>
> It also results in no fixup table being generated for platforms which
> have complex v:p translations (cns3xxx, iop13xx, ixp2xxx, ks8695,
> realview, s3c24a0).
Obviously.
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index dd6b369..bcc502f 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -93,6 +93,9 @@ ENTRY(stext)
> #ifdef CONFIG_SMP_ON_UP
> bl __fixup_smp
> #endif
> +#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
> + bl __fixup_pv_table
> +#endif
> bl __create_page_tables
>
> /*
> @@ -426,4 +429,37 @@ smp_on_up:
>
> #endif
>
> +#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
> +
> +/* __fixup_pv_table - patch the stub instructions with the delta between
> + * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
> + * can be expressed by an immediate shifter operand. The stub instruction
> + * has a form of '(add|sub) rd, rn, #imm'.
> + */
> +__fixup_pv_table:
> + adr r0, 1f
> + ldmia r0, {r3-r5}
> + sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
> + mov r6, r3, lsr #24 @ constant for add/sub instructions
> + teq r3, r6, lsl #24 @ must be 16MiB aligned
> + bne __error
> + orr r6, r6, #0x400 @ mask in rotate right 8 bits
> + add r4, r4, r3
> + add r5, r5, r3
> +2: cmp r4, r5
> + ldrlo r7, [r4], #4
> + ldrlo ip, [r7, r3]
> + bic ip, ip, #0x000000ff
> + bic ip, ip, #0x00000f00
> + orr ip, ip, r6
The above 3 insns could be replaced with:
mov ip, ip, lsr #12
orr ip, r6, ip, lsl #12
> + strlo ip, [r7, r3]
> + blo 2b
> + mov pc, lr
> +ENDPROC(__fixup_phys_virt)
Nicolas
More information about the linux-arm-kernel
mailing list