]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat/kvm/x86: Make SMP init code resolve its own `start16` relocations
authorSergiu Moga <sergiu.moga@protonmail.com>
Wed, 22 Mar 2023 18:57:22 +0000 (20:57 +0200)
committerUnikraft <monkey@unikraft.io>
Fri, 11 Aug 2023 08:11:27 +0000 (08:11 +0000)
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 <sergiu.moga@protonmail.com>
Reviewed-by: Dragos Petre <dragos.petre27@gmail.com>
Reviewed-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Razvan Deaconescu <razvand@unikraft.io>
Approved-by: Razvan Deaconescu <razvand@unikraft.io>
Tested-by: Unikraft CI <monkey@unikraft.io>
GitHub-Closes: #772

plat/common/x86/lcpu.c
plat/common/x86/start16_helpers.h [new file with mode: 0644]
plat/kvm/x86/lcpu_start.S

index 35e6b7f0f99ca09b5d00269fe6b3c890c518c0cd..574b20d08143a3830453dd923c823bb9270033cf 100644 (file)
 
 #include <uk/plat/lcpu.h>
 #include <uk/plat/common/lcpu.h>
+#include <uk/reloc.h>
 
 #include <string.h>
 #include <errno.h>
 
+#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 (file)
index 0000000..af80153
--- /dev/null
@@ -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__ */
index 57f1dd10a2b773a03c8dddbba416a0114132bc18..6e2227ee23f02e1320511bca20a10ebf6c48f6eb 100644 (file)
@@ -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