f49f6b053763d1e729b68b870b1b64ffe09d4504
[linux-2.6-microblaze.git] / arch / loongarch / kernel / relocate_kernel.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * relocate_kernel.S for kexec
4  *
5  * Copyright (C) 2022 Loongson Technology Corporation Limited
6  */
7
8 #include <linux/kexec.h>
9
10 #include <asm/asm.h>
11 #include <asm/asmmacro.h>
12 #include <asm/regdef.h>
13 #include <asm/loongarch.h>
14 #include <asm/stackframe.h>
15 #include <asm/addrspace.h>
16
17 SYM_CODE_START(relocate_new_kernel)
18         /*
19          * a0: EFI boot flag for the new kernel
20          * a1: Command line pointer for the new kernel
21          * a2: System table pointer for the new kernel
22          * a3: Start address to jump to after relocation
23          * a4: Pointer to the current indirection page entry
24          */
25         move            s0, a4
26
27         /*
28          * In case of a kdump/crash kernel, the indirection page is not
29          * populated as the kernel is directly copied to a reserved location
30          */
31         beqz            s0, done
32
33 process_entry:
34         PTR_L           s1, s0, 0
35         PTR_ADDI        s0, s0, SZREG
36
37         /* destination page */
38         andi            s2, s1, IND_DESTINATION
39         beqz            s2, 1f
40         li.w            t0, ~0x1
41         and             s3, s1, t0      /* store destination addr in s3 */
42         b               process_entry
43
44 1:
45         /* indirection page, update s0  */
46         andi            s2, s1, IND_INDIRECTION
47         beqz            s2, 1f
48         li.w            t0, ~0x2
49         and             s0, s1, t0
50         b               process_entry
51
52 1:
53         /* done page */
54         andi            s2, s1, IND_DONE
55         beqz            s2, 1f
56         b               done
57
58 1:
59         /* source page */
60         andi            s2, s1, IND_SOURCE
61         beqz            s2, process_entry
62         li.w            t0, ~0x8
63         and             s1, s1, t0
64         li.w            s5, (1 << _PAGE_SHIFT) / SZREG
65
66 copy_word:
67         /* copy page word by word */
68         REG_L           s4, s1, 0
69         REG_S           s4, s3, 0
70         PTR_ADDI        s3, s3, SZREG
71         PTR_ADDI        s1, s1, SZREG
72         LONG_ADDI       s5, s5, -1
73         beqz            s5, process_entry
74         b               copy_word
75
76 done:
77         ibar            0
78         dbar            0
79
80         /*
81          * Jump to the new kernel,
82          * make sure the values of a0, a1, a2 and a3 are not changed.
83          */
84         jr              a3
85 SYM_CODE_END(relocate_new_kernel)
86
87 #ifdef CONFIG_SMP
88 /*
89  * Other CPUs should wait until code is relocated and
90  * then start at the entry point from LOONGARCH_IOCSR_MBUF0.
91  */
92 SYM_CODE_START(kexec_smp_wait)
93 1:      li.w            t0, 0x100                       /* wait for init loop */
94 2:      addi.w          t0, t0, -1                      /* limit mailbox access */
95         bnez            t0, 2b
96         li.w            t1, LOONGARCH_IOCSR_MBUF0
97         iocsrrd.w       s0, t1                          /* check PC as an indicator */
98         beqz            s0, 1b
99         iocsrrd.d       s0, t1                          /* get PC via mailbox */
100
101         li.d            t0, CACHE_BASE
102         or              s0, s0, t0                      /* s0 = TO_CACHE(s0) */
103         jr              s0                              /* jump to initial PC */
104 SYM_CODE_END(kexec_smp_wait)
105 #endif
106
107 relocate_new_kernel_end:
108
109 SYM_DATA_START(relocate_new_kernel_size)
110         PTR             relocate_new_kernel_end - relocate_new_kernel
111 SYM_DATA_END(relocate_new_kernel_size)