Merge branch 'p2v' into devel
Russell King [Wed, 16 Mar 2011 23:35:27 +0000 (23:35 +0000)]
Conflicts:
arch/arm/kernel/module.c
arch/arm/mach-s5pv210/sleep.S

1  2 
arch/arm/Kconfig
arch/arm/kernel/armksyms.c
arch/arm/kernel/head.S
arch/arm/kernel/module.c
arch/arm/kernel/setup.c
arch/arm/kernel/vmlinux.lds.S

Simple merge
Simple merge
@@@ -425,31 -444,132 +434,156 @@@ smp_on_up
        ALT_SMP(.long   1)
        ALT_UP(.long    0)
        .popsection
 +#endif
  
 +      .text
 +__do_fixup_smp_on_up:
 +      cmp     r4, r5
 +      movhs   pc, lr
 +      ldmia   r4!, {r0, r6}
 + ARM( str     r6, [r0, r3]    )
 + THUMB(       add     r0, r0, r3      )
 +#ifdef __ARMEB__
 + THUMB(       mov     r6, r6, ror #16 )       @ Convert word order for big-endian.
  #endif
 + THUMB(       strh    r6, [r0], #2    )       @ For Thumb-2, store as two halfwords
 + THUMB(       mov     r6, r6, lsr #16 )       @ to be robust against misaligned r3.
 + THUMB(       strh    r6, [r0]        )
 +      b       __do_fixup_smp_on_up
 +ENDPROC(__do_fixup_smp_on_up)
 +
 +ENTRY(fixup_smp)
 +      stmfd   sp!, {r4 - r6, lr}
 +      mov     r4, r0
 +      add     r5, r0, r1
 +      mov     r3, #0
 +      bl      __do_fixup_smp_on_up
 +      ldmfd   sp!, {r4 - r6, pc}
 +ENDPROC(fixup_smp)
  
+ #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'.
+  */
+       __HEAD
+ __fixup_pv_table:
+       adr     r0, 1f
+       ldmia   r0, {r3-r5, r7}
+       sub     r3, r0, r3      @ PHYS_OFFSET - PAGE_OFFSET
+       add     r4, r4, r3      @ adjust table start address
+       add     r5, r5, r3      @ adjust table end address
+       add     r7, r7, r3      @ adjust __pv_phys_offset address
+       str     r8, [r7]        @ save computed PHYS_OFFSET to __pv_phys_offset
+ #ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+       mov     r6, r3, lsr #24 @ constant for add/sub instructions
+       teq     r3, r6, lsl #24 @ must be 16MiB aligned
+ #else
+       mov     r6, r3, lsr #16 @ constant for add/sub instructions
+       teq     r3, r6, lsl #16 @ must be 64kiB aligned
+ #endif
+ THUMB(        it      ne              @ cross section branch )
+       bne     __error
+       str     r6, [r7, #4]    @ save to __pv_offset
+       b       __fixup_a_pv_table
+ ENDPROC(__fixup_pv_table)
+       .align
+ 1:    .long   .
+       .long   __pv_table_begin
+       .long   __pv_table_end
+ 2:    .long   __pv_phys_offset
+       .text
+ __fixup_a_pv_table:
+ #ifdef CONFIG_THUMB2_KERNEL
+ #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+       lsls    r0, r6, #24
+       lsr     r6, #8
+       beq     1f
+       clz     r7, r0
+       lsr     r0, #24
+       lsl     r0, r7
+       bic     r0, 0x0080
+       lsrs    r7, #1
+       orrcs   r0, #0x0080
+       orr     r0, r0, r7, lsl #12
+ #endif
+ 1:    lsls    r6, #24
+       beq     4f
+       clz     r7, r6
+       lsr     r6, #24
+       lsl     r6, r7
+       bic     r6, #0x0080
+       lsrs    r7, #1
+       orrcs   r6, #0x0080
+       orr     r6, r6, r7, lsl #12
+       orr     r6, #0x4000
+       b       4f
+ 2:    @ at this point the C flag is always clear
+       add     r7, r3
+ #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+       ldrh    ip, [r7]
+       tst     ip, 0x0400      @ the i bit tells us LS or MS byte
+       beq     3f
+       cmp     r0, #0          @ set C flag, and ...
+       biceq   ip, 0x0400      @ immediate zero value has a special encoding
+       streqh  ip, [r7]        @ that requires the i bit cleared
+ #endif
+ 3:    ldrh    ip, [r7, #2]
+       and     ip, 0x8f00
+       orrcc   ip, r6  @ mask in offset bits 31-24
+       orrcs   ip, r0  @ mask in offset bits 23-16
+       strh    ip, [r7, #2]
+ 4:    cmp     r4, r5
+       ldrcc   r7, [r4], #4    @ use branch for delay slot
+       bcc     2b
+       bx      lr
+ #else
+ #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+       and     r0, r6, #255    @ offset bits 23-16
+       mov     r6, r6, lsr #8  @ offset bits 31-24
+ #else
+       mov     r0, #0          @ just in case...
+ #endif
+       b       3f
+ 2:    ldr     ip, [r7, r3]
+       bic     ip, ip, #0x000000ff
+       tst     ip, #0x400      @ rotate shift tells us LS or MS byte
+       orrne   ip, ip, r6      @ mask in offset bits 31-24
+       orreq   ip, ip, r0      @ mask in offset bits 23-16
+       str     ip, [r7, r3]
+ 3:    cmp     r4, r5
+       ldrcc   r7, [r4], #4    @ use branch for delay slot
+       bcc     2b
+       mov     pc, lr
+ #endif
+ ENDPROC(__fixup_a_pv_table)
+ ENTRY(fixup_pv_table)
+       stmfd   sp!, {r4 - r7, lr}
+       ldr     r2, 2f                  @ get address of __pv_phys_offset
+       mov     r3, #0                  @ no offset
+       mov     r4, r0                  @ r0 = table start
+       add     r5, r0, r1              @ r1 = table size
+       ldr     r6, [r2, #4]            @ get __pv_offset
+       bl      __fixup_a_pv_table
+       ldmfd   sp!, {r4 - r7, pc}
+ ENDPROC(fixup_pv_table)
+       .align
+ 2:    .long   __pv_phys_offset
+       .data
+       .globl  __pv_phys_offset
+       .type   __pv_phys_offset, %object
+ __pv_phys_offset:
+       .long   0
+       .size   __pv_phys_offset, . - __pv_phys_offset
+ __pv_offset:
+       .long   0
+ #endif
  #include "head-common.S"
@@@ -283,7 -281,7 +283,8 @@@ static const Elf_Shdr *find_mod_section
        return NULL;
  }
  
+ extern void fixup_pv_table(const void *, unsigned long);
 +extern void fixup_smp(const void *, unsigned long);
  
  int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                    struct module *mod)
                                                 maps[i].txt_sec->sh_addr,
                                                 maps[i].txt_sec->sh_size);
  #endif
+ #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+       s = find_mod_section(hdr, sechdrs, ".pv_table");
+       if (s)
+               fixup_pv_table((void *)s->sh_addr, s->sh_size);
+ #endif
 +      s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
 +      if (s && !is_smp())
 +              fixup_smp((void *)s->sh_addr, s->sh_size);
        return 0;
  }
  
Simple merge
Simple merge