powerpc/44x: Enable CONFIG_RELOCATABLE for PPC44x
authorSuzuki Poulose <suzuki@in.ibm.com>
Wed, 14 Dec 2011 22:59:24 +0000 (22:59 +0000)
committerJosh Boyer <jwboyer@gmail.com>
Tue, 20 Dec 2011 15:21:57 +0000 (10:21 -0500)
The following patch adds relocatable kernel support - based on processing
of dynamic relocations - for PPC44x kernel.

We find the runtime address of _stext and relocate ourselves based
on the following calculation.

virtual_base = ALIGN(KERNELBASE,256M) +
MODULO(_stext.run,256M)

relocate() is called with the Effective Virtual Base Address (as
shown below)

            | Phys. Addr| Virt. Addr |
Page (256M) |------------------------|
Boundary    |           |            |
            |           |            |
            |           |            |
Kernel Load |___________|_ __ _ _ _ _|<- Effective
Addr(_stext)|           |      ^     |Virt. Base Addr
            |           |      |     |
            |           |      |     |
            |           |reloc_offset|
            |           |      |     |
            |           |      |     |
            |           |______v_____|<-(KERNELBASE)%256M
            |           |            |
            |           |            |
            |           |            |
Page(256M)  |-----------|------------|
Boundary    |           |            |

The virt_phys_offset is updated accordingly, i.e,

virt_phys_offset = effective. kernel virt base - kernstart_addr

I have tested the patches on 440x platforms only. However this should
work fine for PPC_47x also, as we only depend on the runtime address
and the current TLB XLAT entry for the startup code, which is available
in r25. I don't have access to a 47x board yet. So, it would be great if
somebody could test this on 47x.

Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Tony Breeds <tony@bakeyournoodle.com>
Cc: Josh Boyer <jwboyer@gmail.com>
Cc: linuxppc-dev <linuxppc-dev@lists.ozlabs.org>
Signed-off-by: Josh Boyer <jwboyer@gmail.com>
arch/powerpc/Kconfig
arch/powerpc/kernel/head_44x.S

index 2ad5ea8278200bc876e49b8852da313f2310650b..1703509649b0fed7e7a34d2d137fea271ff83ee0 100644 (file)
@@ -851,7 +851,7 @@ config DYNAMIC_MEMSTART
 
 config RELOCATABLE
        bool "Build a relocatable kernel (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM
+       depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && 44x
        select NONSTATIC_KERNEL
        help
          This builds a kernel image that is capable of running at the
index 0878bf5d8a68c98476cff2eebdc79894b4865834..7dd2981bcc50579a059f3a6fb446660d133eed2a 100644 (file)
@@ -64,6 +64,35 @@ _ENTRY(_start);
        mr      r31,r3          /* save device tree ptr */
        li      r24,0           /* CPU number */
 
+#ifdef CONFIG_RELOCATABLE
+/*
+ * Relocate ourselves to the current runtime address.
+ * This is called only by the Boot CPU.
+ * "relocate" is called with our current runtime virutal
+ * address.
+ * r21 will be loaded with the physical runtime address of _stext
+ */
+       bl      0f                              /* Get our runtime address */
+0:     mflr    r21                             /* Make it accessible */
+       addis   r21,r21,(_stext - 0b)@ha
+       addi    r21,r21,(_stext - 0b)@l         /* Get our current runtime base */
+
+       /*
+        * We have the runtime (virutal) address of our base.
+        * We calculate our shift of offset from a 256M page.
+        * We could map the 256M page we belong to at PAGE_OFFSET and
+        * get going from there.
+        */
+       lis     r4,KERNELBASE@h
+       ori     r4,r4,KERNELBASE@l
+       rlwinm  r6,r21,0,4,31                   /* r6 = PHYS_START % 256M */
+       rlwinm  r5,r4,0,4,31                    /* r5 = KERNELBASE % 256M */
+       subf    r3,r5,r6                        /* r3 = r6 - r5 */
+       add     r3,r4,r3                        /* Required Virutal Address */
+
+       bl      relocate
+#endif
+
        bl      init_cpu_state
 
        /*
@@ -86,7 +115,64 @@ _ENTRY(_start);
 
        bl      early_init
 
-#ifdef CONFIG_DYNAMIC_MEMSTART
+#ifdef CONFIG_RELOCATABLE
+       /*
+        * Relocatable kernel support based on processing of dynamic
+        * relocation entries.
+        *
+        * r25 will contain RPN/ERPN for the start address of memory
+        * r21 will contain the current offset of _stext
+        */
+       lis     r3,kernstart_addr@ha
+       la      r3,kernstart_addr@l(r3)
+
+       /*
+        * Compute the kernstart_addr.
+        * kernstart_addr => (r6,r8)
+        * kernstart_addr & ~0xfffffff => (r6,r7)
+        */
+       rlwinm  r6,r25,0,28,31  /* ERPN. Bits 32-35 of Address */
+       rlwinm  r7,r25,0,0,3    /* RPN - assuming 256 MB page size */
+       rlwinm  r8,r21,0,4,31   /* r8 = (_stext & 0xfffffff) */
+       or      r8,r7,r8        /* Compute the lower 32bit of kernstart_addr */
+
+       /* Store kernstart_addr */
+       stw     r6,0(r3)        /* higher 32bit */
+       stw     r8,4(r3)        /* lower 32bit  */
+
+       /*
+        * Compute the virt_phys_offset :
+        * virt_phys_offset = stext.run - kernstart_addr
+        *
+        * stext.run = (KERNELBASE & ~0xfffffff) + (kernstart_addr & 0xfffffff)
+        * When we relocate, we have :
+        *
+        *      (kernstart_addr & 0xfffffff) = (stext.run & 0xfffffff)
+        *
+        * hence:
+        *  virt_phys_offset = (KERNELBASE & ~0xfffffff) - (kernstart_addr & ~0xfffffff)
+        *
+        */
+
+       /* KERNELBASE&~0xfffffff => (r4,r5) */
+       li      r4, 0           /* higer 32bit */
+       lis     r5,KERNELBASE@h
+       rlwinm  r5,r5,0,0,3     /* Align to 256M, lower 32bit */
+
+       /*
+        * 64bit subtraction.
+        */
+       subfc   r5,r7,r5
+       subfe   r4,r6,r4
+
+       /* Store virt_phys_offset */
+       lis     r3,virt_phys_offset@ha
+       la      r3,virt_phys_offset@l(r3)
+
+       stw     r4,0(r3)
+       stw     r5,4(r3)
+
+#elif defined(CONFIG_DYNAMIC_MEMSTART)
        /*
         * Mapping based, page aligned dynamic kernel loading.
         *
@@ -804,7 +890,12 @@ skpinv:    addi    r4,r4,1                         /* Increment */
 /*
  * Configure and load pinned entry into TLB slot 63.
  */
-#ifdef CONFIG_DYNAMIC_MEMSTART
+#ifdef CONFIG_NONSTATIC_KERNEL
+       /*
+        * In case of a NONSTATIC_KERNEL we reuse the TLB XLAT
+        * entries of the initial mapping set by the boot loader.
+        * The XLAT entry is stored in r25
+        */
 
        /* Read the XLAT entry for our current mapping */
        tlbre   r25,r23,PPC44x_TLB_XLAT