diff options
author | David Brazdil <dbrazdil@google.com> | 2021-01-05 18:05:38 +0000 |
---|---|---|
committer | Marc Zyngier <maz@kernel.org> | 2021-01-23 14:01:00 +0000 |
commit | 6ec6259d7084ed32e164c9f7b69049464dd90fa5 (patch) | |
tree | 775107adfbbf9d41e3591b1083b4f194e9177a07 /arch/arm64/kvm/va_layout.c | |
parent | 8c49b5d43d4c45ca0bb0d1faa23feef2e76e89fa (diff) | |
download | linux-stable-6ec6259d7084ed32e164c9f7b69049464dd90fa5.tar.gz linux-stable-6ec6259d7084ed32e164c9f7b69049464dd90fa5.tar.bz2 linux-stable-6ec6259d7084ed32e164c9f7b69049464dd90fa5.zip |
KVM: arm64: Apply hyp relocations at runtime
KVM nVHE code runs under a different VA mapping than the kernel, hence
so far it avoided using absolute addressing because the VA in a constant
pool is relocated by the linker to a kernel VA (see hyp_symbol_addr).
Now the kernel has access to a list of positions that contain a kimg VA
but will be accessed only in hyp execution context. These are generated
by the gen-hyprel build-time tool and stored in .hyp.reloc.
Add early boot pass over the entries and convert the kimg VAs to hyp VAs.
Note that this requires for .hyp* ELF sections to be mapped read-write
at that point.
Signed-off-by: David Brazdil <dbrazdil@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210105180541.65031-6-dbrazdil@google.com
Diffstat (limited to 'arch/arm64/kvm/va_layout.c')
-rw-r--r-- | arch/arm64/kvm/va_layout.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c index 70fcd6a12fe1..fee7dcd95d73 100644 --- a/arch/arm64/kvm/va_layout.c +++ b/arch/arm64/kvm/va_layout.c @@ -81,6 +81,34 @@ __init void kvm_compute_layout(void) init_hyp_physvirt_offset(); } +/* + * The .hyp.reloc ELF section contains a list of kimg positions that + * contains kimg VAs but will be accessed only in hyp execution context. + * Convert them to hyp VAs. See gen-hyprel.c for more details. + */ +__init void kvm_apply_hyp_relocations(void) +{ + int32_t *rel; + int32_t *begin = (int32_t *)__hyp_reloc_begin; + int32_t *end = (int32_t *)__hyp_reloc_end; + + for (rel = begin; rel < end; ++rel) { + uintptr_t *ptr, kimg_va; + + /* + * Each entry contains a 32-bit relative offset from itself + * to a kimg VA position. + */ + ptr = (uintptr_t *)lm_alias((char *)rel + *rel); + + /* Read the kimg VA value at the relocation address. */ + kimg_va = *ptr; + + /* Convert to hyp VA and store back to the relocation address. */ + *ptr = __early_kern_hyp_va((uintptr_t)lm_alias(kimg_va)); + } +} + static u32 compute_instruction(int n, u32 rd, u32 rn) { u32 insn = AARCH64_BREAK_FAULT; |