From: Sergiu Moga Date: Wed, 22 Mar 2023 18:57:22 +0000 (+0200) Subject: plat/kvm/x86: Make SMP init code resolve its own `start16` relocations X-Git-Tag: RELEASE-0.14.0~144 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=cf8cc65cb0ae;p=unikraft%2Funikraft.git plat/kvm/x86: Make SMP init code resolve its own `start16` relocations Before waking up the secondary cores, the SMP initialization code copies the, now position independent through `uk_reloc`, 16-bit and 32-bit bootstrapping code to a physical page, in the lower 1 Mib of physical memory. Since, at this point of execution, the immediate values used by this bootstrapping code take the form of `UK_RELOC_PLACEHOLDER`, they will need to be properly resolved after being moved into lower memory. Therefore, add a new locally defined `struct uk_reloc` array holding the hardcoded corresponding entries of these relocations, adapted to reference the desired relocation address. Use this array after memory copying the bootstrapping code to lower memory to resolve its corresponding `start16` relocations. Encode these entries with the help of `start16` related macro's and since these definitions are starting to visually occupy a lot of space, move everything to `start16_helpers.h`, a separate header file. Signed-off-by: Sergiu Moga Reviewed-by: Dragos Petre Reviewed-by: Michalis Pappas Reviewed-by: Razvan Deaconescu Approved-by: Razvan Deaconescu Tested-by: Unikraft CI GitHub-Closes: #772 --- diff --git a/plat/common/x86/lcpu.c b/plat/common/x86/lcpu.c index 35e6b7f0f..574b20d08 100644 --- a/plat/common/x86/lcpu.c +++ b/plat/common/x86/lcpu.c @@ -46,10 +46,15 @@ #include #include +#include #include #include +#if CONFIG_LIBUKRELOC +#include "start16_helpers.h" +#endif /* CONFIG_LIBUKRELOC */ + __lcpuid lcpu_arch_id(void) { __u32 eax, ebx, ecx, edx; @@ -106,11 +111,42 @@ void __noreturn lcpu_arch_jump_to(void *sp, ukplat_lcpu_entry_t entry) * corresponding boot code somewhere in the first 1 MiB. We copy the trampoline * code to the target address during MP initialization. */ -extern __vaddr_t x86_start16_addr; /* target address */ -extern void *x86_start16_begin[]; -extern void *x86_start16_end[]; -#define X86_START16_SIZE \ - ((__uptr)x86_start16_end - (__uptr)x86_start16_begin) +#if CONFIG_LIBUKRELOC +IMPORT_START16_UKRELOC_SYM(gdt32_ptr, 2, MOV); +IMPORT_START16_UKRELOC_SYM(gdt32, 4, DATA); +IMPORT_START16_UKRELOC_SYM(lcpu_start16, 2, MOV); +IMPORT_START16_UKRELOC_SYM(jump_to32, 2, MOV); +IMPORT_START16_UKRELOC_SYM(lcpu_start32, 4, MOV); + +static void uk_reloc_mp_init(void) +{ + size_t i; + struct uk_reloc x86_start16_relocs[] = { + START16_UKRELOC_ENTRY(lcpu_start16, 2, MOV), + START16_UKRELOC_ENTRY(gdt32, 4, DATA), + START16_UKRELOC_ENTRY(gdt32_ptr, 2, MOV), + START16_UKRELOC_ENTRY(jump_to32, 2, MOV), + }; + + for (i = 0; i < ARRAY_SIZE(x86_start16_relocs); i++) + apply_uk_reloc(&x86_start16_relocs[i], + (__u64)x86_start16_addr + + x86_start16_relocs[i].r_addr, + (void *)x86_start16_addr); + + /* Unlike the other entries, lcpu_start32 must stay the same + * as it is not part of the start16 section + */ + apply_uk_reloc(&(struct uk_reloc)UKRELOC_ENTRY( + START16_UKRELOC_MOV_OFF(lcpu_start32, 4), + (__u64)lcpu_start32, 4, + UKRELOC_FLAGS_PHYS_REL), + (__u64)lcpu_start32, + (void *)x86_start16_addr); +} +#else /* CONFIG_LIBUKRELOC */ +static void uk_reloc_mp_init(void) { } +#endif /* !CONFIG_LIBUKRELOC */ int lcpu_arch_mp_init(void *arg __unused) { @@ -181,6 +217,9 @@ int lcpu_arch_mp_init(void *arg __unused) UK_ASSERT(x86_start16_addr < 0x100000); memcpy((void *)x86_start16_addr, &x86_start16_begin, X86_START16_SIZE); + + uk_reloc_mp_init(); + uk_pr_debug("Copied AP 16-bit boot code to 0x%"__PRIvaddr"\n", x86_start16_addr); diff --git a/plat/common/x86/start16_helpers.h b/plat/common/x86/start16_helpers.h new file mode 100644 index 000000000..af801539d --- /dev/null +++ b/plat/common/x86/start16_helpers.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ + +#ifndef __START16_HELPERS_H__ +#define __START16_HELPERS_H__ + +extern __vaddr_t x86_start16_addr; /* target address */ +extern void *x86_start16_begin[]; +extern void *x86_start16_end[]; + +#define X86_START16_SIZE \ + ((__uptr)x86_start16_end - (__uptr)x86_start16_begin) + +#define START16_UKRELOC_MOV_SYM(sym, sz) \ + sym##_uk_reloc_imm##sz##_start16 + +#define START16_UKRELOC_DATA_SYM(sym, sz) \ + sym##_uk_reloc_data##sz##_start16 + +#define IMPORT_START16_UKRELOC_SYM(sym, sz, type) \ + extern void *sym[]; \ + extern void *START16_UKRELOC_##type##_SYM(sym, sz)[] + +#define START16_UKRELOC_MOV_OFF(sym, sz) \ + ((void *)START16_UKRELOC_MOV_SYM(sym, sz) - \ + (void *)x86_start16_begin) + +#define START16_UKRELOC_DATA_OFF(sym, sz) \ + ((void *)START16_UKRELOC_DATA_SYM(sym, sz) - \ + (void *)x86_start16_begin) + +#define START16_UKRELOC_ENTRY(sym, sz, type) \ + UKRELOC_ENTRY(START16_UKRELOC_##type##_OFF(sym, sz), \ + (void *)sym - (void *)x86_start16_begin, \ + sz, UKRELOC_FLAGS_PHYS_REL) + +#endif /* __START16_HELPERS_H__ */ diff --git a/plat/kvm/x86/lcpu_start.S b/plat/kvm/x86/lcpu_start.S index 57f1dd10a..6e2227ee2 100644 --- a/plat/kvm/x86/lcpu_start.S +++ b/plat/kvm/x86/lcpu_start.S @@ -57,6 +57,10 @@ x86_start16_addr: * the existence of 16-bit code. This is so it does not interfere with the other * uses of the ur_* macro's. For example, we not want symbols for these to * occupy unnecessary space in .uk_reloc. + * + * NOTE:IF ADDING/REMOVING RELOCATIONS FROM HERE, THEN ADD/REMOVE + * CORRESPONDENT SYMBOL TO `lcpu.c` (see IMPORT_START16_UKRELOC_SYM + * start16_helpers.h macros being used on start16 symbols) */ .macro ur_mov_start16 sym:req, reg:req, bytes:req mov $START16_PLACEHOLDER, \reg @@ -107,6 +111,7 @@ END(lcpu_start16_ap) * It is only used as entry point for APs in SMP configuration. */ .align 16 +.globl gdt32 gdt32: /* We can repurpose the null segment to encode the GDT pointer because * the null segment is not accessed by the processor in 32-bit mode. We also @@ -115,6 +120,7 @@ gdt32: */ gdt32_null: .word 0x0000 +.globl gdt32_ptr gdt32_ptr: .word (gdt32_end - gdt32 - 1) /* size - 1 */ ur_data_start16 long, gdt32, 4 /* GDT address */ @@ -160,6 +166,7 @@ ENTRY(lcpu_start16) ljmp $(gdt32_cs - gdt32), $START16_PLACEHOLDER .code32 +.globl jump_to32 jump_to32: /* Set up remaining segment registers */ movl $(gdt32_ds - gdt32), %eax