From f88336fa4a557bd0d010d0b2a1ce3ad97e8f1efb Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Tue, 14 Feb 2023 15:17:11 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Support missing pKVM module sections pKVM modules being rather small, it is expected for some basic sections to be missing or empty (especially rodata and data). Make those optional in the loader. Bug: 269245057 Change-Id: I874050230de5cb4b3b29d316663400bb221e2021 Signed-off-by: Vincent Donnefort --- arch/arm64/kernel/module.c | 51 ++++++++++++++++++-------------------- arch/arm64/kvm/pkvm.c | 12 ++++++--- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index f01d8b3328cb..051fd7a3ba63 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -524,39 +524,36 @@ static int module_init_hyp(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, .end = (void *)s->sh_addr + s->sh_size, }; - s = find_section(hdr, sechdrs, ".hyp.bss"); - if (!s) - return -ENOEXEC; - - mod->arch.hyp.bss = (struct pkvm_module_section) { - .start = (void *)s->sh_addr, - .end = (void *)s->sh_addr + s->sh_size, - }; - - s = find_section(hdr, sechdrs, ".hyp.rodata"); - if (!s) - return -ENOEXEC; - - mod->arch.hyp.rodata = (struct pkvm_module_section) { - .start = (void *)s->sh_addr, - .end = (void *)s->sh_addr + s->sh_size, - }; - - s = find_section(hdr, sechdrs, ".hyp.data"); - if (!s) - return -ENOEXEC; - - mod->arch.hyp.data = (struct pkvm_module_section) { - .start = (void *)s->sh_addr, - .end = (void *)s->sh_addr + s->sh_size, - }; - s = find_section(hdr, sechdrs, ".hyp.reloc"); if (!s) return -ENOEXEC; mod->arch.hyp.relocs = (void *)s->sh_addr; mod->arch.hyp.nr_relocs = s->sh_size / sizeof(*mod->arch.hyp.relocs); + + s = find_section(hdr, sechdrs, ".hyp.bss"); + if (s && s->sh_size) { + mod->arch.hyp.bss = (struct pkvm_module_section) { + .start = (void *)s->sh_addr, + .end = (void *)s->sh_addr + s->sh_size, + }; + } + + s = find_section(hdr, sechdrs, ".hyp.rodata"); + if (s && s->sh_size) { + mod->arch.hyp.rodata = (struct pkvm_module_section) { + .start = (void *)s->sh_addr, + .end = (void *)s->sh_addr + s->sh_size, + }; + } + + s = find_section(hdr, sechdrs, ".hyp.data"); + if (s && s->sh_size) { + mod->arch.hyp.data = (struct pkvm_module_section) { + .start = (void *)s->sh_addr, + .end = (void *)s->sh_addr + s->sh_size, + }; + } #endif return 0; } diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 4ff98340fcb2..cb347c4710a0 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -601,8 +601,8 @@ int __pkvm_load_el2_module(struct module *this, unsigned long *token) }; void *start, *end, *hyp_va; kvm_nvhe_reloc_t *endrel; + int ret, i, secs_first; size_t offset, size; - int ret, i; if (!is_protected_kvm_enabled()) return -EOPNOTSUPP; @@ -619,8 +619,13 @@ int __pkvm_load_el2_module(struct module *this, unsigned long *token) return -ENODEV; } + /* Missing or empty module sections are placed first */ sort(secs_map, ARRAY_SIZE(secs_map), sizeof(secs_map[0]), __pkvm_cmp_mod_sec, NULL); - start = secs_map[0].sec->start; + for (secs_first = 0; secs_first < ARRAY_SIZE(secs_map); secs_first++) { + start = secs_map[secs_first].sec->start; + if (start) + break; + } end = secs_map[ARRAY_SIZE(secs_map) - 1].sec->end; size = end - start; @@ -642,7 +647,8 @@ int __pkvm_load_el2_module(struct module *this, unsigned long *token) endrel = (void *)mod->relocs + mod->nr_relocs * sizeof(*endrel); kvm_apply_hyp_module_relocations(start, hyp_va, mod->relocs, endrel); - ret = pkvm_map_module_sections(secs_map, hyp_va, ARRAY_SIZE(secs_map)); + ret = pkvm_map_module_sections(secs_map + secs_first, hyp_va, + ARRAY_SIZE(secs_map) - secs_first); if (ret) { kvm_err("Failed to map EL2 module page: %d\n", ret); module_put(this);