On Sun, 24 Jul 2011 18:11:14 +0300 Kostik Belousov wrote:

 KB> On Sun, Jul 24, 2011 at 11:02:21AM +0300, Mikolaj Golub wrote:
 >> Also, could someone explain what is kern/link_elf_obj.c for? The patch does
 >> not deal with this file, but I see the reloactions here similar to those in
 >> link_elf.c. So I might need to do similar modifiactions in link_elf_obj.c 
 >> too,
 >> but I don't know where this code is used (it looks like it is not executed 
 >> on
 >> my box, so I don't know how to test it).

 KB> The link_elf_obj is a linker for architectures that use object file format
 KB> for the modules. So far, the list consists only of amd64.

Thanks! And there is no need in hacks with relocations in this case: in
link_elf_load_file() it just allocates space in kernel 'set_vnet' set for
'set_vnet' from the module and sets addr to point to this space.

As the fix appears to be link_elf.c specific and the code is used only in this
file I have modified the patch placing set_vnet list and its functions in
link_elf.c.

-- 
Mikolaj Golub

Index: sys/kern/link_elf.c
===================================================================
--- sys/kern/link_elf.c	(revision 224397)
+++ sys/kern/link_elf.c	(working copy)
@@ -123,6 +123,17 @@ typedef struct elf_file {
 #endif
 } *elf_file_t;
 
+#ifdef VIMAGE
+struct set_vnet {
+	uintptr_t       vs_start;
+	uintptr_t       vs_stop;
+	uintptr_t	vs_base;
+	TAILQ_ENTRY(set_vnet)	vs_link;
+};
+
+static TAILQ_HEAD(set_vnet_head, set_vnet) set_vnet_list;
+#endif
+
 #include <kern/kern_ctf.c>
 
 static int	link_elf_link_common_finish(linker_file_t);
@@ -345,6 +356,9 @@ link_elf_init(void* arg)
 
 	(void)link_elf_link_common_finish(linker_kernel_file);
 	linker_kernel_file->flags |= LINKER_FILE_LINKED;
+#ifdef VIMAGE
+	TAILQ_INIT(&set_vnet_list);
+#endif
 }
 
 SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_THIRD, link_elf_init, 0);
@@ -520,7 +534,89 @@ parse_dpcpu(elf_file_t ef)
 }
 
 #ifdef VIMAGE
+static void
+set_vnet_insert(struct set_vnet *set)
+{
+	struct set_vnet *iter;
+
+	TAILQ_FOREACH(iter, &set_vnet_list, vs_link) {
+
+		KASSERT((set->vs_start < iter->vs_start && set->vs_stop < iter->vs_stop) ||
+		    (set->vs_start > iter->vs_start && set->vs_stop > iter->vs_stop),
+		    ("vnet sets intersection: to insert: 0x%jx-0x%jx; inserted: 0x%jx-0x%jx",
+		    (uintmax_t)set->vs_start, (uintmax_t)set->vs_stop,
+		    (uintmax_t)iter->vs_start, (uintmax_t)iter->vs_stop));
+
+		if (iter->vs_start > set->vs_start) {
+			TAILQ_INSERT_BEFORE(iter, set, vs_link);
+			break;
+		}
+	}
+
+	if (iter == NULL)
+		TAILQ_INSERT_TAIL(&set_vnet_list, set, vs_link);
+}
+
+static void
+set_vnet_remove(struct set_vnet *set)
+{
+	TAILQ_REMOVE(&set_vnet_list, set, vs_link);
+}
+
+static struct set_vnet *
+set_vnet_search(uintptr_t addr)
+{
+	struct set_vnet *set;
+
+	TAILQ_FOREACH(set, &set_vnet_list, vs_link) {
+		if (addr < set->vs_start)
+			return (NULL);
+		if (addr < set->vs_stop)
+			return (set);
+	}
+	return (NULL);
+}
+
+static void
+set_vnet_add(uintptr_t start, uintptr_t stop, uintptr_t base)
+{
+	struct set_vnet *set;
+
+	set = malloc(sizeof(*set), M_LINKER, M_WAITOK);
+	set->vs_start = start;
+	set->vs_stop = stop;
+	set->vs_base = base;
+	set_vnet_insert(set);
+}
+
+static void
+set_vnet_delete(uintptr_t start)
+{
+	struct set_vnet *set;
+
+	set = set_vnet_search(start);
+	KASSERT(set != NULL, ("deleting unknown vnet set (start = 0x%jx)",
+	    (uintmax_t)start));
+	set_vnet_remove(set);
+	free(set, M_LINKER);
+}
+
 static int
+set_vnet_find(uintptr_t addr, uintptr_t *start, uintptr_t *base)
+{
+	struct set_vnet *set;
+
+	set = set_vnet_search(addr);
+	if (set != NULL) {
+		*start = set->vs_start;
+		*base = set->vs_base;
+		return (1);
+	} else {
+		return (0);
+	}
+}
+
+static int
 parse_vnet(elf_file_t ef)
 { 
 	int count;
@@ -544,6 +640,7 @@ parse_vnet(elf_file_t ef)
 		return (ENOSPC);
 	memcpy((void *)ef->vnet_base, (void *)ef->vnet_start, count);
 	vnet_data_copy((void *)ef->vnet_base, count);
+	set_vnet_add(ef->vnet_start, ef->vnet_stop, ef->vnet_base);
 
 	return (0);
 }
@@ -1000,6 +1097,7 @@ link_elf_unload_file(linker_file_t file)
 	if (ef->vnet_base != 0) {
 		vnet_data_free((void *)ef->vnet_base,
 		    ef->vnet_stop - ef->vnet_start);
+		set_vnet_delete(ef->vnet_start);
 	}
 #endif
 #ifdef GDB
@@ -1438,6 +1536,10 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int
 	elf_file_t ef = (elf_file_t)lf;
 	const Elf_Sym *sym;
 	const char *symbol;
+	Elf_Addr addr;
+#ifdef VIMAGE
+	uintptr_t vnet_start, vnet_base;
+#endif
 
 	/* Don't even try to lookup the symbol if the index is bogus. */
 	if (symidx >= ef->nchains)
@@ -1469,7 +1571,13 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int
 	if (*symbol == 0)
 		return (0);
 
-	return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
+	addr = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
+
+#ifdef VIMAGE
+	if (set_vnet_find(addr, &vnet_start, &vnet_base))
+		addr = addr - vnet_start + vnet_base;
+#endif
+	return addr;
 }
 
 static void
_______________________________________________
freebsd-virtualization@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-virtualization
To unsubscribe, send any mail to 
"freebsd-virtualization-unsubscr...@freebsd.org"

Reply via email to