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        /* destination page */
  30        and             s3, s2, 0x1
  31        beq             s3, zero, 1f
  32        and             s4, s2, ~0x1    /* store destination addr in s4 */
  33        b               process_entry
  34
  351:
  36        /* indirection page, update s0  */
  37        and             s3, s2, 0x2
  38        beq             s3, zero, 1f
  39        and             s0, s2, ~0x2
  40        b               process_entry
  41
  421:
  43        /* done page */
  44        and             s3, s2, 0x4
  45        beq             s3, zero, 1f
  46        b               done
  471:
  48        /* source page */
  49        and             s3, s2, 0x8
  50        beq             s3, zero, process_entry
  51        and             s2, s2, ~0x8
  52        li              s6, (1 << _PAGE_SHIFT) / SZREG
  53
  54copy_word:
  55        /* copy page word by word */
  56        REG_L           s5, (s2)
  57        REG_S           s5, (s4)
  58        PTR_ADD         s4, s4, SZREG
  59        PTR_ADD         s2, s2, SZREG
  60        LONG_SUB        s6, s6, 1
  61        beq             s6, zero, process_entry
  62        b               copy_word
  63        b               process_entry
  64
  65done:
  66#ifdef CONFIG_SMP
  67        /* kexec_flag reset is signal to other CPUs what kernel
  68           was moved to it's location. Note - we need relocated address
  69           of kexec_flag.  */
  70
  71        bal             1f
  72 1:     move            t1,ra;
  73        PTR_LA          t2,1b
  74        PTR_LA          t0,kexec_flag
  75        PTR_SUB         t0,t0,t2;
  76        PTR_ADD         t0,t1,t0;
  77        LONG_S          zero,(t0)
  78#endif
  79
  80#ifdef CONFIG_CPU_CAVIUM_OCTEON
  81        /* We need to flush I-cache before jumping to new kernel.
  82         * Unfortunatelly, this code is cpu-specific.
  83         */
  84        .set push
  85        .set noreorder
  86        syncw
  87        syncw
  88        synci           0($0)
  89        .set pop
  90#else
  91        sync
  92#endif
  93        /* jump to kexec_start_address */
  94        j               s1
  95        END(relocate_new_kernel)
  96
  97#ifdef CONFIG_SMP
  98/*
  99 * Other CPUs should wait until code is relocated and
 100 * then start at entry (?) point.
 101 */
 102LEAF(kexec_smp_wait)
 103        PTR_L           a0, s_arg0
 104        PTR_L           a1, s_arg1
 105        PTR_L           a2, s_arg2
 106        PTR_L           a3, s_arg3
 107        PTR_L           s1, kexec_start_address
 108
 109        /* Non-relocated address works for args and kexec_start_address ( old
 110         * kernel is not overwritten). But we need relocated address of
 111         * kexec_flag.
 112         */
 113
 114        bal             1f
 1151:      move            t1,ra;
 116        PTR_LA          t2,1b
 117        PTR_LA          t0,kexec_flag
 118        PTR_SUB         t0,t0,t2;
 119        PTR_ADD         t0,t1,t0;
 120
 1211:      LONG_L          s0, (t0)
 122        bne             s0, zero,1b
 123
 124#ifdef CONFIG_CPU_CAVIUM_OCTEON
 125        .set push
 126        .set noreorder
 127        synci           0($0)
 128        .set pop
 129#else
 130        sync
 131#endif
 132        j               s1
 133        END(kexec_smp_wait)
 134#endif
 135
 136#ifdef __mips64
 137       /* all PTR's must be aligned to 8 byte in 64-bit mode */
 138       .align  3
 139#endif
 140
 141/* All parameters to new kernel are passed in registers a0-a3.
 142 * kexec_args[0..3] are uses to prepare register values.
 143 */
 144
 145kexec_args:
 146        EXPORT(kexec_args)
 147arg0:   PTR             0x0
 148arg1:   PTR             0x0
 149arg2:   PTR             0x0
 150arg3:   PTR             0x0
 151        .size   kexec_args,PTRSIZE*4
 152
 153#ifdef CONFIG_SMP
 154/*
 155 * Secondary CPUs may have different kernel parameters in
 156 * their registers a0-a3. secondary_kexec_args[0..3] are used
 157 * to prepare register values.
 158 */
 159secondary_kexec_args:
 160        EXPORT(secondary_kexec_args)
 161s_arg0: PTR             0x0
 162s_arg1: PTR             0x0
 163s_arg2: PTR             0x0
 164s_arg3: PTR             0x0
 165        .size   secondary_kexec_args,PTRSIZE*4
 166kexec_flag:
 167        LONG            0x1
 168
 169#endif
 170
 171kexec_start_address:
 172        EXPORT(kexec_start_address)
 173        PTR             0x0
 174        .size           kexec_start_address, PTRSIZE
 175
 176kexec_indirection_page:
 177        EXPORT(kexec_indirection_page)
 178        PTR             0
 179        .size           kexec_indirection_page, PTRSIZE
 180
 181relocate_new_kernel_end:
 182
 183relocate_new_kernel_size:
 184        EXPORT(relocate_new_kernel_size)
 185        PTR             relocate_new_kernel_end - relocate_new_kernel
 186        .size           relocate_new_kernel_size, PTRSIZE
 187