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
17SYM_CODE_START(relocate_new_kernel)
18 UNWIND_HINT_UNDEFINED
19 /*
20 * a0: EFI boot flag for the new kernel
21 * a1: Command line pointer for the new kernel
22 * a2: System table pointer for the new kernel
23 * a3: Start address to jump to after relocation
24 * a4: Pointer to the current indirection page entry
25 */
26 move s0, a4
27
28 /*
29 * In case of a kdump/crash kernel, the indirection page is not
30 * populated as the kernel is directly copied to a reserved location
31 */
32 beqz s0, done
33
34process_entry:
35 PTR_L s1, s0, 0
36 PTR_ADDI s0, s0, SZREG
37
38 /* destination page */
39 andi s2, s1, IND_DESTINATION
40 beqz s2, 1f
41 li.w t0, ~0x1
42 and s3, s1, t0 /* store destination addr in s3 */
43 b process_entry
44
451:
46 /* indirection page, update s0 */
47 andi s2, s1, IND_INDIRECTION
48 beqz s2, 1f
49 li.w t0, ~0x2
50 and s0, s1, t0
51 b process_entry
52
531:
54 /* done page */
55 andi s2, s1, IND_DONE
56 beqz s2, 1f
57 b done
58
591:
60 /* source page */
61 andi s2, s1, IND_SOURCE
62 beqz s2, process_entry
63 li.w t0, ~0x8
64 and s1, s1, t0
65 li.w s5, (1 << _PAGE_SHIFT) / SZREG
66
67copy_word:
68 /* copy page word by word */
69 REG_L s4, s1, 0
70 REG_S s4, s3, 0
71 PTR_ADDI s3, s3, SZREG
72 PTR_ADDI s1, s1, SZREG
73 LONG_ADDI s5, s5, -1
74 beqz s5, process_entry
75 b copy_word
76
77done:
78 ibar 0
79 dbar 0
80
81 /*
82 * Jump to the new kernel,
83 * make sure the values of a0, a1, a2 and a3 are not changed.
84 */
85 jr a3
86SYM_CODE_END(relocate_new_kernel)
87
88#ifdef CONFIG_SMP
89/*
90 * Other CPUs should wait until code is relocated and
91 * then start at the entry point from LOONGARCH_IOCSR_MBUF0.
92 */
93SYM_CODE_START(kexec_smp_wait)
94 UNWIND_HINT_UNDEFINED
951: li.w t0, 0x100 /* wait for init loop */
962: addi.w t0, t0, -1 /* limit mailbox access */
97 bnez t0, 2b
98 li.w t1, LOONGARCH_IOCSR_MBUF0
99 iocsrrd.w s0, t1 /* check PC as an indicator */
100 beqz s0, 1b
101 iocsrrd.d s0, t1 /* get PC via mailbox */
102
103 li.d t0, CACHE_BASE
104 or s0, s0, t0 /* s0 = TO_CACHE(s0) */
105 jr s0 /* jump to initial PC */
106SYM_CODE_END(kexec_smp_wait)
107#endif
108
109relocate_new_kernel_end:
110
111 .section ".data"
112SYM_DATA(relocate_new_kernel_size, .long relocate_new_kernel_end - relocate_new_kernel)
113

source code of linux/arch/loongarch/kernel/relocate_kernel.S