linux/arch/mips/kernel/relocate_kernel.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * relocate_kernel.S for kexec
   4 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
   5 */
   6
   7#include <asm/asm.h>
   8#include <asm/asmmacro.h>
   9#include <asm/regdef.h>
  10#include <asm/mipsregs.h>
  11#include <asm/stackframe.h>
  12#include <asm/addrspace.h>
  13
  14#include <kernel-entry-init.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_ADDIU       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_ADDIU       s4, s4, SZREG
  65        PTR_ADDIU       s2, s2, SZREG
  66        LONG_ADDIU      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         * Unfortunately, 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 USE_KEXEC_SMP_WAIT_FINAL
 131        kexec_smp_wait_final
 132#else
 133        sync
 134#endif
 135        j               s1
 136        END(kexec_smp_wait)
 137#endif
 138
 139#ifdef __mips64
 140       /* all PTR's must be aligned to 8 byte in 64-bit mode */
 141       .align  3
 142#endif
 143
 144/* All parameters to new kernel are passed in registers a0-a3.
 145 * kexec_args[0..3] are used to prepare register values.
 146 */
 147
 148kexec_args:
 149        EXPORT(kexec_args)
 150arg0:   PTR             0x0
 151arg1:   PTR             0x0
 152arg2:   PTR             0x0
 153arg3:   PTR             0x0
 154        .size   kexec_args,PTRSIZE*4
 155
 156#ifdef CONFIG_SMP
 157/*
 158 * Secondary CPUs may have different kernel parameters in
 159 * their registers a0-a3. secondary_kexec_args[0..3] are used
 160 * to prepare register values.
 161 */
 162secondary_kexec_args:
 163        EXPORT(secondary_kexec_args)
 164s_arg0: PTR             0x0
 165s_arg1: PTR             0x0
 166s_arg2: PTR             0x0
 167s_arg3: PTR             0x0
 168        .size   secondary_kexec_args,PTRSIZE*4
 169kexec_flag:
 170        LONG            0x1
 171
 172#endif
 173
 174kexec_start_address:
 175        EXPORT(kexec_start_address)
 176        PTR             0x0
 177        .size           kexec_start_address, PTRSIZE
 178
 179kexec_indirection_page:
 180        EXPORT(kexec_indirection_page)
 181        PTR             0
 182        .size           kexec_indirection_page, PTRSIZE
 183
 184relocate_new_kernel_end:
 185
 186relocate_new_kernel_size:
 187        EXPORT(relocate_new_kernel_size)
 188        PTR             relocate_new_kernel_end - relocate_new_kernel
 189        .size           relocate_new_kernel_size, PTRSIZE
 190