linux/arch/mips/kernel/relocate_kernel.S
<<
>>
Prefs
   1/*
   2 * relocate_kernel.S for kexec
   3 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
   4 *
   5 * This source code is licensed under the GNU General Public License,
   6 * Version 2.  See the file COPYING for more details.
   7 */
   8
   9#include <asm/asm.h>
  10#include <asm/asmmacro.h>
  11#include <asm/regdef.h>
  12#include <asm/mipsregs.h>
  13#include <asm/stackframe.h>
  14#include <asm/addrspace.h>
  15
  16LEAF(relocate_new_kernel)
  17        PTR_L a0,       arg0
  18        PTR_L a1,       arg1
  19        PTR_L a2,       arg2
  20        PTR_L a3,       arg3
  21
  22        PTR_L           s0, kexec_indirection_page
  23        PTR_L           s1, kexec_start_address
  24
  25process_entry:
  26        PTR_L           s2, (s0)
  27        PTR_ADD         s0, s0, SZREG
  28
  29        /*
  30         * In case of a kdump/crash kernel, the indirection page is not
  31         * populated as the kernel is directly copied to a reserved location
  32         */
  33        beqz            s2, done
  34
  35        /* destination page */
  36        and             s3, s2, 0x1
  37        beq             s3, zero, 1f
  38        and             s4, s2, ~0x1    /* store destination addr in s4 */
  39        b               process_entry
  40
  411:
  42        /* indirection page, update s0  */
  43        and             s3, s2, 0x2
  44        beq             s3, zero, 1f
  45        and             s0, s2, ~0x2
  46        b               process_entry
  47
  481:
  49        /* done page */
  50        and             s3, s2, 0x4
  51        beq             s3, zero, 1f
  52        b               done
  531:
  54        /* source page */
  55        and             s3, s2, 0x8
  56        beq             s3, zero, process_entry
  57        and             s2, s2, ~0x8
  58        li              s6, (1 << _PAGE_SHIFT) / SZREG
  59
  60copy_word:
  61        /* copy page word by word */
  62        REG_L           s5, (s2)
  63        REG_S           s5, (s4)
  64        PTR_ADD         s4, s4, SZREG
  65        PTR_ADD         s2, s2, SZREG
  66        LONG_SUB        s6, s6, 1
  67        beq             s6, zero, process_entry
  68        b               copy_word
  69        b               process_entry
  70
  71done:
  72#ifdef CONFIG_SMP
  73        /* kexec_flag reset is signal to other CPUs what kernel
  74           was moved to it's location. Note - we need relocated address
  75           of kexec_flag.  */
  76
  77        bal             1f
  78 1:     move            t1,ra;
  79        PTR_LA          t2,1b
  80        PTR_LA          t0,kexec_flag
  81        PTR_SUB         t0,t0,t2;
  82        PTR_ADD         t0,t1,t0;
  83        LONG_S          zero,(t0)
  84#endif
  85
  86#ifdef CONFIG_CPU_CAVIUM_OCTEON
  87        /* We need to flush I-cache before jumping to new kernel.
  88         * Unfortunatelly, this code is cpu-specific.
  89         */
  90        .set push
  91        .set noreorder
  92        syncw
  93        syncw
  94        synci           0($0)
  95        .set pop
  96#else
  97        sync
  98#endif
  99        /* jump to kexec_start_address */
 100        j               s1
 101        END(relocate_new_kernel)
 102
 103#ifdef CONFIG_SMP
 104/*
 105 * Other CPUs should wait until code is relocated and
 106 * then start at entry (?) point.
 107 */
 108LEAF(kexec_smp_wait)
 109        PTR_L           a0, s_arg0
 110        PTR_L           a1, s_arg1
 111        PTR_L           a2, s_arg2
 112        PTR_L           a3, s_arg3
 113        PTR_L           s1, kexec_start_address
 114
 115        /* Non-relocated address works for args and kexec_start_address ( old
 116         * kernel is not overwritten). But we need relocated address of
 117         * kexec_flag.
 118         */
 119
 120        bal             1f
 1211:      move            t1,ra;
 122        PTR_LA          t2,1b
 123        PTR_LA          t0,kexec_flag
 124        PTR_SUB         t0,t0,t2;
 125        PTR_ADD         t0,t1,t0;
 126
 1271:      LONG_L          s0, (t0)
 128        bne             s0, zero,1b
 129
 130#ifdef CONFIG_CPU_CAVIUM_OCTEON
 131        .set push
 132        .set noreorder
 133        synci           0($0)
 134        .set pop
 135#else
 136        sync
 137#endif
 138        j               s1
 139        END(kexec_smp_wait)
 140#endif
 141
 142#ifdef __mips64
 143       /* all PTR's must be aligned to 8 byte in 64-bit mode */
 144       .align  3
 145#endif
 146
 147/* All parameters to new kernel are passed in registers a0-a3.
 148 * kexec_args[0..3] are uses to prepare register values.
 149 */
 150
 151kexec_args:
 152        EXPORT(kexec_args)
 153arg0:   PTR             0x0
 154arg1:   PTR             0x0
 155arg2:   PTR             0x0
 156arg3:   PTR             0x0
 157        .size   kexec_args,PTRSIZE*4
 158
 159#ifdef CONFIG_SMP
 160/*
 161 * Secondary CPUs may have different kernel parameters in
 162 * their registers a0-a3. secondary_kexec_args[0..3] are used
 163 * to prepare register values.
 164 */
 165secondary_kexec_args:
 166        EXPORT(secondary_kexec_args)
 167s_arg0: PTR             0x0
 168s_arg1: PTR             0x0
 169s_arg2: PTR             0x0
 170s_arg3: PTR             0x0
 171        .size   secondary_kexec_args,PTRSIZE*4
 172kexec_flag:
 173        LONG            0x1
 174
 175#endif
 176
 177kexec_start_address:
 178        EXPORT(kexec_start_address)
 179        PTR             0x0
 180        .size           kexec_start_address, PTRSIZE
 181
 182kexec_indirection_page:
 183        EXPORT(kexec_indirection_page)
 184        PTR             0
 185        .size           kexec_indirection_page, PTRSIZE
 186
 187relocate_new_kernel_end:
 188
 189relocate_new_kernel_size:
 190        EXPORT(relocate_new_kernel_size)
 191        PTR             relocate_new_kernel_end - relocate_new_kernel
 192        .size           relocate_new_kernel_size, PTRSIZE
 193