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 <vdonnefort@google.com>
This commit is contained in:
Vincent Donnefort
2023-02-14 15:17:11 +00:00
parent 116e1532b9
commit f88336fa4a
2 changed files with 33 additions and 30 deletions

View File

@@ -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;
}

View File

@@ -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);