mirror of
https://github.com/YusufOzmen01/quest-kexec.git
synced 2026-10-26 19:37:39 +00:00
182 lines
3.8 KiB
ArmAsm
182 lines
3.8 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Quest Pro: EL1, 4K pages, 39-bit VA. No stack use after TTBR0 switch.
|
|
* The relocation loop follows Linux arm64's relocate_kernel.S cache rules.
|
|
*/
|
|
#include <linux/linkage.h>
|
|
#include <asm/assembler.h>
|
|
#include <asm/sysreg.h>
|
|
|
|
.text
|
|
.align 4
|
|
/* x0: private identity PGD, x1: physical control page, x2: descriptor head,
|
|
* x3: Image entry, x4: DTB. The high module mapping remains in TTBR1.
|
|
*/
|
|
ENTRY(qkx_enter)
|
|
msr daifset, #0xf
|
|
/* First invalidate the old TTBR0 translations with walks disabled. */
|
|
mrs x9, tcr_el1
|
|
orr x9, x9, #(1 << 7)
|
|
msr tcr_el1, x9
|
|
isb
|
|
dsb ishst
|
|
tlbi vmalle1
|
|
dsb ish
|
|
isb
|
|
msr ttbr0_el1, x0
|
|
/* T0SZ=25, TG0=4K; preserve cacheability/shareability and TTBR1. */
|
|
bic x9, x9, #0x3f
|
|
mov x10, #25
|
|
orr x9, x9, x10
|
|
bic x9, x9, #(3 << 14)
|
|
bic x9, x9, #(1 << 37)
|
|
bic x9, x9, #(1 << 7)
|
|
msr tcr_el1, x9
|
|
isb
|
|
br x1
|
|
ENDPROC(qkx_enter)
|
|
|
|
/* Copied to a separately allocated physical page. No external references. */
|
|
.align 4
|
|
ENTRY(qkx_reloc_start)
|
|
mov x17, x3
|
|
mov x18, x4
|
|
mov x19, x2
|
|
mrs x9, sctlr_el1
|
|
ldr x10, =SCTLR_ELx_FLAGS
|
|
bic x9, x9, x10
|
|
pre_disable_mmu_workaround
|
|
msr sctlr_el1, x9
|
|
isb
|
|
raw_dcache_line_size x15, x9
|
|
1:
|
|
cbz x19, 5f
|
|
/* Descriptor pages: { next, count, { source, destination }[255] }. */
|
|
ldp x20, x21, [x19]
|
|
add x19, x19, #16
|
|
2:
|
|
cbz x21, 4f
|
|
ldp x22, x23, [x19], #16
|
|
mov x9, x23
|
|
add x10, x23, #4096
|
|
3:
|
|
dc ivac, x9
|
|
add x9, x9, x15
|
|
cmp x9, x10
|
|
b.lo 3b
|
|
dsb sy
|
|
/* PAGE_SIZE bytes, both addresses page-aligned and nonoverlapping. */
|
|
mov x11, #256
|
|
6:
|
|
ldp x9, x10, [x22], #16
|
|
stp x9, x10, [x23], #16
|
|
subs x11, x11, #1
|
|
b.ne 6b
|
|
sub x21, x21, #1
|
|
b 2b
|
|
4:
|
|
mov x19, x20
|
|
b 1b
|
|
5:
|
|
dsb sy
|
|
ic iallu
|
|
dsb sy
|
|
isb
|
|
mov x0, x18
|
|
mov x1, xzr
|
|
mov x2, xzr
|
|
mov x3, xzr
|
|
br x17
|
|
.ltorg
|
|
qkx_reloc_end:
|
|
ENDPROC(qkx_reloc_start)
|
|
.global qkx_reloc_end
|
|
|
|
/* Reversible test of the very same TTBR0/physical/MMU-off transition.
|
|
* x0..x4 are passed through to the physical code. The relocation loop uses
|
|
* x17..x23, so preserve every callee-saved register and keep the translation
|
|
* state in x24..x27 until the original SCTLR is restored and control returns
|
|
* high.
|
|
*/
|
|
.align 4
|
|
ENTRY(qkx_roundtrip)
|
|
stp x19, x20, [sp, #-96]!
|
|
stp x21, x22, [sp, #16]
|
|
stp x23, x24, [sp, #32]
|
|
stp x25, x26, [sp, #48]
|
|
stp x27, x28, [sp, #64]
|
|
str x30, [sp, #80]
|
|
mrs x24, tcr_el1
|
|
mrs x25, ttbr0_el1
|
|
mrs x26, sctlr_el1
|
|
adr x27, .Lroundtrip_return
|
|
orr x9, x24, #(1 << 7)
|
|
msr tcr_el1, x9
|
|
isb
|
|
dsb ishst
|
|
tlbi vmalle1
|
|
dsb ish
|
|
isb
|
|
msr ttbr0_el1, x0
|
|
bic x9, x9, #0x3f
|
|
mov x10, #25
|
|
orr x9, x9, x10
|
|
bic x9, x9, #(3 << 14)
|
|
bic x9, x9, #(1 << 37)
|
|
bic x9, x9, #(1 << 7)
|
|
msr tcr_el1, x9
|
|
isb
|
|
br x1
|
|
.Lroundtrip_return:
|
|
/* Disable TTBR0 walks before restoring the saved translation context. */
|
|
mrs x9, tcr_el1
|
|
orr x9, x9, #(1 << 7)
|
|
msr tcr_el1, x9
|
|
isb
|
|
msr ttbr0_el1, x25
|
|
dsb ishst
|
|
tlbi vmalle1
|
|
dsb ish
|
|
isb
|
|
msr tcr_el1, x24
|
|
isb
|
|
ldr x30, [sp, #80]
|
|
ldp x27, x28, [sp, #64]
|
|
ldp x25, x26, [sp, #48]
|
|
ldp x23, x24, [sp, #32]
|
|
ldp x21, x22, [sp, #16]
|
|
ldp x19, x20, [sp], #96
|
|
ret
|
|
ENDPROC(qkx_roundtrip)
|
|
|
|
.align 4
|
|
ENTRY(qkx_probe_phys_start)
|
|
mrs x9, sctlr_el1
|
|
ldr x10, =SCTLR_ELx_FLAGS
|
|
bic x9, x9, x10
|
|
pre_disable_mmu_workaround
|
|
msr sctlr_el1, x9
|
|
isb
|
|
mrs x0, sctlr_el1
|
|
and x0, x0, x10
|
|
/* Result zero proves the cleared flags were read back while physical. */
|
|
msr sctlr_el1, x26
|
|
isb
|
|
br x27
|
|
.ltorg
|
|
.global qkx_probe_phys_end
|
|
qkx_probe_phys_end:
|
|
ENDPROC(qkx_probe_phys_start)
|
|
|
|
/* Appended to the copied relocation code for its reversible scratch test.
|
|
* qkx_reloc_start leaves the completion value in x0, restores SCTLR here,
|
|
* then returns through the high mapping saved by qkx_roundtrip.
|
|
*/
|
|
.align 4
|
|
ENTRY(qkx_reloc_return_start)
|
|
msr sctlr_el1, x26
|
|
isb
|
|
br x27
|
|
.global qkx_reloc_return_end
|
|
qkx_reloc_return_end:
|
|
ENDPROC(qkx_reloc_return_start)
|