Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: kexec: configure EL2 vectors for kexec

If we have a EL2 mode without VHE, the EL2 vectors are needed in order
to switch to EL2 and jump to new world with hypervisor privileges.

In preparation to MMU enabled relocation, configure our EL2 table now.

Kexec uses #HVC_SOFT_RESTART to branch to the new world, so extend
el1_sync vector that is provided by trans_pgd_copy_el2_vectors() to
support this case.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20210930143113.1502553-9-pasha.tatashin@soleen.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Pasha Tatashin and committed by
Will Deacon
08eae0ef 878fdbd7

+42 -2
+1 -1
arch/arm64/Kconfig
··· 1135 1135 1136 1136 config TRANS_TABLE 1137 1137 def_bool y 1138 - depends on HIBERNATION 1138 + depends on HIBERNATION || KEXEC_CORE 1139 1139 1140 1140 config XEN_DOM0 1141 1141 def_bool y
+1
arch/arm64/include/asm/kexec.h
··· 96 96 void *dtb; 97 97 phys_addr_t dtb_mem; 98 98 phys_addr_t kern_reloc; 99 + phys_addr_t el2_vectors; 99 100 }; 100 101 101 102 #ifdef CONFIG_KEXEC_FILE
+1
arch/arm64/kernel/asm-offsets.c
··· 174 174 #endif 175 175 #ifdef CONFIG_KEXEC_CORE 176 176 DEFINE(KIMAGE_ARCH_DTB_MEM, offsetof(struct kimage, arch.dtb_mem)); 177 + DEFINE(KIMAGE_ARCH_EL2_VECTORS, offsetof(struct kimage, arch.el2_vectors)); 177 178 DEFINE(KIMAGE_HEAD, offsetof(struct kimage, head)); 178 179 DEFINE(KIMAGE_START, offsetof(struct kimage, start)); 179 180 BLANK();
+31
arch/arm64/kernel/machine_kexec.c
··· 21 21 #include <asm/mmu.h> 22 22 #include <asm/mmu_context.h> 23 23 #include <asm/page.h> 24 + #include <asm/trans_pgd.h> 24 25 25 26 #include "cpu-reset.h" 26 27 ··· 44 43 pr_debug(" start: %lx\n", kimage->start); 45 44 pr_debug(" head: %lx\n", kimage->head); 46 45 pr_debug(" nr_segments: %lu\n", kimage->nr_segments); 46 + pr_debug(" dtb_mem: %pa\n", &kimage->arch.dtb_mem); 47 47 pr_debug(" kern_reloc: %pa\n", &kimage->arch.kern_reloc); 48 + pr_debug(" el2_vectors: %pa\n", &kimage->arch.el2_vectors); 48 49 49 50 for (i = 0; i < kimage->nr_segments; i++) { 50 51 pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n", ··· 146 143 } 147 144 } 148 145 146 + /* Allocates pages for kexec page table */ 147 + static void *kexec_page_alloc(void *arg) 148 + { 149 + struct kimage *kimage = (struct kimage *)arg; 150 + struct page *page = kimage_alloc_control_pages(kimage, 0); 151 + 152 + if (!page) 153 + return NULL; 154 + 155 + memset(page_address(page), 0, PAGE_SIZE); 156 + 157 + return page_address(page); 158 + } 159 + 149 160 int machine_kexec_post_load(struct kimage *kimage) 150 161 { 151 162 void *reloc_code = page_to_virt(kimage->control_code_page); 163 + struct trans_pgd_info info = { 164 + .trans_alloc_page = kexec_page_alloc, 165 + .trans_alloc_arg = kimage, 166 + }; 152 167 153 168 /* If in place, relocation is not used, only flush next kernel */ 154 169 if (kimage->head & IND_DONE) { 155 170 kexec_segment_flush(kimage); 156 171 kexec_image_info(kimage); 157 172 return 0; 173 + } 174 + 175 + kimage->arch.el2_vectors = 0; 176 + if (is_hyp_nvhe()) { 177 + int rc = trans_pgd_copy_el2_vectors(&info, 178 + &kimage->arch.el2_vectors); 179 + if (rc) 180 + return rc; 158 181 } 159 182 160 183 memcpy(reloc_code, arm64_relocate_new_kernel, ··· 238 209 restart(is_hyp_nvhe(), kimage->start, kimage->arch.dtb_mem, 239 210 0, 0); 240 211 } else { 212 + if (is_hyp_nvhe()) 213 + __hyp_set_vectors(kimage->arch.el2_vectors); 241 214 cpu_soft_restart(kimage->arch.kern_reloc, virt_to_phys(kimage), 242 215 0, 0); 243 216 }
+8 -1
arch/arm64/mm/trans_pgd-asm.S
··· 24 24 msr vbar_el2, x1 25 25 mov x0, xzr 26 26 eret 27 - 1: /* Unexpected argument, set an error */ 27 + 1: cmp x0, #HVC_SOFT_RESTART /* Called from kexec */ 28 + b.ne 2f 29 + mov x0, x2 30 + mov x2, x4 31 + mov x4, x1 32 + mov x1, x3 33 + br x4 34 + 2: /* Unexpected argument, set an error */ 28 35 mov_q x0, HVC_STUB_ERR 29 36 eret 30 37 SYM_CODE_END(el1_sync)