#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;
* 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)
{
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);
--- /dev/null
+/* 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__ */
* 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
* 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
*/
gdt32_null:
.word 0x0000
+.globl gdt32_ptr
gdt32_ptr:
.word (gdt32_end - gdt32 - 1) /* size - 1 */
ur_data_start16 long, gdt32, 4 /* GDT address */
ljmp $(gdt32_cs - gdt32), $START16_PLACEHOLDER
.code32
+.globl jump_to32
jump_to32:
/* Set up remaining segment registers */
movl $(gdt32_ds - gdt32), %eax