| 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 | |
| 9 |
|
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 |
|
| 17 | SYM_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 |
|
| 34 | process_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 |
|
| 45 | 1:
|
| 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 |
|
| 53 | 1:
|
| 54 | /* done page */
|
| 55 | andi s2, s1, IND_DONE
|
| 56 | beqz s2, 1f
|
| 57 | b done
|
| 58 |
|
| 59 | 1:
|
| 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 |
|
| 67 | copy_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 |
|
| 77 | done:
|
| 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
|
| 86 | SYM_CODE_END(relocate_new_kernel)
|
| 87 |
|
| 88 | |
| 89 | /*
|
| 90 | * Other CPUs should wait until code is relocated and
|
| 91 | * then start at the entry point from LOONGARCH_IOCSR_MBUF0.
|
| 92 | */
|
| 93 | SYM_CODE_START(kexec_smp_wait)
|
| 94 | UNWIND_HINT_UNDEFINED
|
| 95 | 1: li.w t0, 0x100 /* wait for init loop */
|
| 96 | 2: 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 */
|
| 106 | SYM_CODE_END(kexec_smp_wait)
|
| 107 | |
| 108 |
|
| 109 | relocate_new_kernel_end:
|
| 110 |
|
| 111 | .section ".data"
|
| 112 | SYM_DATA(relocate_new_kernel_size, .quad relocate_new_kernel_end - relocate_new_kernel)
|