powerpc: enable the relocatable support for the fsl booke 32bit kernel
authorKevin Hao <haokexin@gmail.com>
Tue, 24 Dec 2013 07:12:06 +0000 (15:12 +0800)
committerScott Wood <scottwood@freescale.com>
Thu, 9 Jan 2014 23:52:16 +0000 (17:52 -0600)
This is based on the codes in the head_44x.S. The difference is that
the init tlb size we used is 64M. With this patch we can only load the
kernel at address between memstart_addr ~ memstart_addr + 64M. We will
fix this restriction in the following patches.

Signed-off-by: Kevin Hao <haokexin@gmail.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/Kconfig
arch/powerpc/kernel/fsl_booke_entry_mapping.S
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/mm/fsl_booke_mmu.c

index f0a8931..4bb52e6 100644 (file)
@@ -884,7 +884,7 @@ config DYNAMIC_MEMSTART
 
 config RELOCATABLE
        bool "Build a relocatable kernel"
-       depends on ADVANCED_OPTIONS && FLATMEM && 44x
+       depends on ADVANCED_OPTIONS && FLATMEM && (44x || FSL_BOOKE)
        select NONSTATIC_KERNEL
        help
          This builds a kernel image that is capable of running at the
index a92c79b..f22e7e4 100644 (file)
@@ -176,6 +176,8 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 /* 7. Jump to KERNELBASE mapping */
        lis     r6,(KERNELBASE & ~0xfff)@h
        ori     r6,r6,(KERNELBASE & ~0xfff)@l
+       rlwinm  r7,r25,0,0x03ffffff
+       add     r6,r7,r6
 
 #elif defined(ENTRY_MAPPING_KEXEC_SETUP)
 /*
index 196950f..19bd574 100644 (file)
@@ -73,6 +73,30 @@ _ENTRY(_start);
        li      r24,0                   /* CPU number */
        li      r23,0                   /* phys kernel start (high) */
 
+#ifdef CONFIG_RELOCATABLE
+       LOAD_REG_ADDR_PIC(r3, _stext)   /* Get our current runtime base */
+
+       /* Translate _stext address to physical, save in r23/r25 */
+       bl      get_phys_addr
+       mr      r23,r3
+       mr      r25,r4
+
+       /*
+        * We have the runtime (virutal) address of our base.
+        * We calculate our shift of offset from a 64M page.
+        * We could map the 64M page we belong to at PAGE_OFFSET and
+        * get going from there.
+        */
+       lis     r4,KERNELBASE@h
+       ori     r4,r4,KERNELBASE@l
+       rlwinm  r6,r25,0,0x3ffffff              /* r6 = PHYS_START % 64M */
+       rlwinm  r5,r4,0,0x3ffffff               /* r5 = KERNELBASE % 64M */
+       subf    r3,r5,r6                        /* r3 = r6 - r5 */
+       add     r3,r4,r3                        /* Required Virtual Address */
+
+       bl      relocate
+#endif
+
 /* We try to not make any assumptions about how the boot loader
  * setup or used the TLBs.  We invalidate all mappings from the
  * boot loader and load a single entry in TLB1[0] to map the
@@ -182,6 +206,16 @@ _ENTRY(__early_start)
 
        bl      early_init
 
+#ifdef CONFIG_RELOCATABLE
+#ifdef CONFIG_PHYS_64BIT
+       mr      r3,r23
+       mr      r4,r25
+#else
+       mr      r3,r25
+#endif
+       bl      relocate_init
+#endif
+
 #ifdef CONFIG_DYNAMIC_MEMSTART
        lis     r3,kernstart_addr@ha
        la      r3,kernstart_addr@l(r3)
index 07ba45b..ce4a116 100644 (file)
@@ -241,4 +241,32 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
        /* 64M mapped initially according to head_fsl_booke.S */
        memblock_set_current_limit(min_t(u64, limit, 0x04000000));
 }
+
+#ifdef CONFIG_RELOCATABLE
+notrace void __init relocate_init(phys_addr_t start)
+{
+       unsigned long base = KERNELBASE;
+
+       /*
+        * Relocatable kernel support based on processing of dynamic
+        * relocation entries.
+        * Compute the virt_phys_offset :
+        * virt_phys_offset = stext.run - kernstart_addr
+        *
+        * stext.run = (KERNELBASE & ~0x3ffffff) + (kernstart_addr & 0x3ffffff)
+        * When we relocate, we have :
+        *
+        *      (kernstart_addr & 0x3ffffff) = (stext.run & 0x3ffffff)
+        *
+        * hence:
+        *  virt_phys_offset = (KERNELBASE & ~0x3ffffff) -
+        *                              (kernstart_addr & ~0x3ffffff)
+        *
+        */
+       kernstart_addr = start;
+       start &= ~0x3ffffff;
+       base &= ~0x3ffffff;
+       virt_phys_offset = base - start;
+}
+#endif
 #endif