summaryrefslogtreecommitdiff
path: root/sys/kern/link_elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/link_elf.c')
-rw-r--r--sys/kern/link_elf.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index cd0f3e909d5b..b389ace5bd49 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$");
#include <machine/elf.h>
+#include <net/vnet.h>
+
#include <security/mac/mac_framework.h>
#include <vm/vm.h>
@@ -111,6 +113,11 @@ typedef struct elf_file {
Elf_Addr pcpu_start; /* Pre-relocation pcpu set start. */
Elf_Addr pcpu_stop; /* Pre-relocation pcpu set stop. */
Elf_Addr pcpu_base; /* Relocated pcpu set address. */
+#ifdef VIMAGE
+ Elf_Addr vnet_start; /* Pre-relocation vnet set start. */
+ Elf_Addr vnet_stop; /* Pre-relocation vnet set stop. */
+ Elf_Addr vnet_base; /* Relocated vnet set address. */
+#endif
#ifdef GDB
struct link_map gdb; /* hooks for gdb */
#endif
@@ -506,6 +513,36 @@ parse_dpcpu(elf_file_t ef)
return (0);
}
+#ifdef VIMAGE
+static int
+parse_vnet(elf_file_t ef)
+{
+ int count;
+ int error;
+
+ ef->vnet_start = 0;
+ ef->vnet_stop = 0;
+ error = link_elf_lookup_set(&ef->lf, "vnet", (void ***)&ef->vnet_start,
+ (void ***)&ef->vnet_stop, &count);
+ /* Error just means there is no vnet data set to relocate. */
+ if (error)
+ return (0);
+ count *= sizeof(void *);
+ /*
+ * Allocate space in the primary vnet area. Copy in our initialization
+ * from the data section and then initialize all per-vnet storage from
+ * that.
+ */
+ ef->vnet_base = (Elf_Addr)(uintptr_t)vnet_data_alloc(count);
+ if (ef->vnet_base == (Elf_Addr)NULL)
+ return (ENOSPC);
+ memcpy((void *)ef->vnet_base, (void *)ef->vnet_start, count);
+ vnet_data_copy((void *)ef->vnet_base, count);
+
+ return (0);
+}
+#endif
+
static int
link_elf_link_preload(linker_class_t cls,
const char* filename, linker_file_t *result)
@@ -553,6 +590,10 @@ link_elf_link_preload(linker_class_t cls,
error = parse_dynamic(ef);
if (error == 0)
error = parse_dpcpu(ef);
+#ifdef VIMAGE
+ if (error == 0)
+ error = parse_vnet(ef);
+#endif
if (error) {
linker_file_unload(lf, LINKER_UNLOAD_FORCE);
return error;
@@ -838,6 +879,11 @@ link_elf_load_file(linker_class_t cls, const char* filename,
error = parse_dpcpu(ef);
if (error)
goto out;
+#ifdef VIMAGE
+ error = parse_vnet(ef);
+ if (error)
+ goto out;
+#endif
link_elf_reloc_local(lf);
VOP_UNLOCK(nd.ni_vp, 0);
@@ -942,6 +988,10 @@ elf_relocaddr(linker_file_t lf, Elf_Addr x)
ef = (elf_file_t)lf;
if (x >= ef->pcpu_start && x < ef->pcpu_stop)
return ((x - ef->pcpu_start) + ef->pcpu_base);
+#ifdef VIMAGE
+ if (x >= ef->vnet_start && x < ef->vnet_stop)
+ return ((x - ef->vnet_start) + ef->vnet_base);
+#endif
return (x);
}
@@ -954,6 +1004,11 @@ link_elf_unload_file(linker_file_t file)
if (ef->pcpu_base) {
dpcpu_free((void *)ef->pcpu_base, ef->pcpu_stop - ef->pcpu_start);
}
+#ifdef VIMAGE
+ if (ef->vnet_base) {
+ vnet_data_free((void *)ef->vnet_base, ef->vnet_stop - ef->vnet_start);
+ }
+#endif
#ifdef GDB
if (ef->gdb.l_ld) {
GDB_STATE(RT_DELETE);