[Cbe-oss-dev] [PATCH 2/2] libspe2 : Add emulated isolation support RESEND

Kanna Shimizu kannas at ofb.net
Sat Jun 30 16:55:38 EST 2007


libspe2: Add emulated isolated mode support

Using a userspace loader, we can add an 'emulated' isolated mode, which
provides a facility to run contexts with an isolated-mode environment,
but without restricted access to SPE hardware. Contexts can be created
in emulated isolated mode by providing the SPE_ISOLATE_EMULATE flag to
spe_context_create.

This functionality depends on an emulated loader - a SPE program to
load the "emulated isolated" SPE application, using the same ABI as the
real isolated mode loader. We check for this in the file:

  $libdir/spe/emulated-loader.bin

- if this isn't present (or isn't a valid SPE binary) then we refuse to
create emulated-isolated contexts.

Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
Signed-off-by: Kanna Shimizu <kannas at us.ibm.com>

Index: libspe2/spebase/Makefile
===================================================================
--- libspe2.orig/spebase/Makefile
+++ libspe2/spebase/Makefile
@@ -23,6 +23,7 @@ include $(TOP)/make.defines
 
 MAJOR_VERSION	:= 2
 MINOR_VERSION	:= 0.0
+EMULATED_LOADER := $(libdir)/spe/emulated-loader.bin
 
 libspebase_A	:= libspebase.a
 libspebase_SO	:= libspebase.so.${MAJOR_VERSION}.${MINOR_VERSION}
@@ -35,6 +36,8 @@ libspebase_OBJS := create.o  elf_loader.
 CFLAGS += -I..
 CFLAGS += -D_ATFILE_SOURCE
 
+load.o: CPPFLAGS+='-DSPE_EMULATED_LOADER_FILE="$(EMULATED_LOADER)"'
+
 all: $(libspebase_SO) $(libspebase_A)
 
 install-so: $(libspebase_SO) $(libspebase_A)
Index: libspe2/libspe2-types.h
===================================================================
--- libspe2.orig/libspe2-types.h
+++ libspe2/libspe2-types.h
@@ -176,6 +176,7 @@ enum ps_area { SPE_MSSYNC_AREA, SPE_MFC_
 #define SPE_CFG_SIGNOTIFY2_OR   0x00000020
 #define SPE_MAP_PS				0x00000040
 #define SPE_ISOLATE				0x00000080
+#define SPE_ISOLATE_EMULATE			0x00000100
 #define SPE_EVENTS_ENABLE			0x00001000
 #define SPE_AFFINITY_MEMORY			0x00002000
 
Index: libspe2/spebase/load.c
===================================================================
--- libspe2.orig/spebase/load.c
+++ libspe2/spebase/load.c
@@ -26,6 +26,10 @@
 #include "elf_loader.h"
 #include "spebase.h"
 
+#ifndef SPE_EMULATED_LOADER_FILE
+#define SPE_EMULATED_LOADER_FILE "/usr/lib/spe/emulated-loader.bin"
+#endif
+
 /**
  * Send data to a SPU in mbox when space is available.
  *
@@ -86,6 +90,74 @@ static int spe_start_isolated_app(struct
 	return 0;
 }
 
+/**
+ * Load the emulated isolation loader program from the filesystem
+ *
+ * @return The loader program, or NULL if it can't be loaded. The loader binary
+ *	   is cached between calls.
+ */
+static spe_program_handle_t *emulated_loader_program(void)
+{
+	static spe_program_handle_t *loader = NULL;
+
+	if (!loader)
+		loader = _base_spe_image_open(SPE_EMULATED_LOADER_FILE);
+
+	if (!loader)
+		DEBUG_PRINTF("Can't load emulated loader '%s': %s\n",
+				SPE_EMULATED_LOADER_FILE, strerror(errno));
+
+	return loader;
+}
+
+/**
+ * Check if the emulated loader is present in the filesystem
+ * @return Non-zero if the loader is available, otherwise zero.
+ */
+int _base_spe_emulated_loader_present(void)
+{
+	spe_program_handle_t *loader = emulated_loader_program();
+
+	if (!loader)
+		return 0;
+
+	return !verify_spe_elf_image(loader);
+}
+
+/**
+ * Initiate transfer of an emulated isolated SPE app by the loader kernel.
+ *
+ * Helper function for internal libspe use.
+ *
+ * @param thread The SPE thread to load the app to
+ * @param handle The handle to the (isolated) spe program
+ * @param ld_info[out] Loader information about the entry point of the SPE.
+ *		This will reference the loader, not the SPE program, as
+ *		we will be running the loader first.
+ * @return zero on success, non-zero on failure;
+ */
+static int spe_start_emulated_isolated_app(struct spe_context *spe,
+		spe_program_handle_t *handle, struct spe_ld_info *ld_info)
+
+{
+	int rc;
+	spe_program_handle_t *loader;
+
+	/* load emulated loader from the filesystem */
+	loader = emulated_loader_program();
+
+	if (!loader)
+		return -1;
+
+	rc = load_spe_elf(loader, spe->base_private->mem_mmap_base, ld_info);
+	if (rc != 0) {
+		DEBUG_PRINTF("%s: No loader available\n", __FUNCTION__);
+		return rc;
+	}
+
+	return spe_start_isolated_app(spe, handle);
+}
+
 int _base_spe_program_load(spe_context_ptr_t spe, spe_program_handle_t *program)
 {
 	int rc = 0, objfd;
@@ -93,6 +165,10 @@ int _base_spe_program_load(spe_context_p
 
 	if (spe->base_private->flags & SPE_ISOLATE) {
 		rc = spe_start_isolated_app(spe, program);
+
+	} else if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
+		rc = spe_start_emulated_isolated_app(spe, program, &ld_info);
+
 	} else {
 		rc = load_spe_elf(program, spe->base_private->mem_mmap_base,
 				&ld_info);
@@ -114,7 +190,8 @@ int _base_spe_program_load(spe_context_p
 	
 	__spe_context_update_event();	
 
-	spe->base_private->entry=ld_info.entry;
-	
+	spe->base_private->entry = ld_info.entry;
+	spe->base_private->emulated_entry = ld_info.entry;
+
 	return 0;
 }
Index: libspe2/spebase/create.c
===================================================================
--- libspe2.orig/spebase/create.c
+++ libspe2/spebase/create.c
@@ -189,6 +189,13 @@ spe_context_ptr_t _base_spe_context_crea
 	struct spe_context *spe = NULL;
 	struct spe_context_base_priv *priv;
 
+	/* We need a loader present to run in emulated isolated mode */
+	if (flags & SPE_ISOLATE_EMULATE
+			&& !_base_spe_emulated_loader_present()) {
+		errno = EINVAL;
+		return NULL;
+	}
+
 	/* Put some sane defaults into the SPE context */
 	spe = malloc(sizeof(*spe));
 	if (!spe) {
Index: libspe2/spebase/spebase.h
===================================================================
--- libspe2.orig/spebase/spebase.h
+++ libspe2/spebase/spebase.h
@@ -91,6 +91,10 @@ struct spe_context_base_priv {
 	
 	/* SPE program entry point generated by elf_load() */
 	int		entry;
+
+	/* We need to keep the entry point for emulated isolated contexts,
+	 * and ignore the value provided to spe_context_run */
+	int		emulated_entry;
 };
 
 
@@ -110,6 +114,12 @@ struct spe_context_base_priv {
 #define SIGNAL1_OFFSET			0x14000
 #define SIGNAL2_OFFSET			0x1c000
 
+/**
+ * Location of the PPE-assisted library call buffer
+ * for emulated isolation contexts.
+ */
+#define SPE_EMULATE_PARAM_BUFFER	0x3e000
+
 /* 
  */
 #define SPE_PROGRAM_NORMAL_END		0x2000
@@ -168,6 +178,12 @@ extern spe_gang_context_ptr_t _base_spe_
 extern int _base_spe_program_load(spe_context_ptr_t spectx, spe_program_handle_t *program);
 
 /**
+ * Check if the emulated loader is present in the filesystem
+ * @return Non-zero if the loader is available, otherwise zero.
+ */
+int _base_spe_emulated_loader_present(void);
+
+/**
  * _base_spe_context_destroy cleans up what is left when an SPE executable has exited. 
  * Closes open file handles and unmaps memory areas.
  * 
Index: libspe2/spebase/run.c
===================================================================
--- libspe2.orig/spebase/run.c
+++ libspe2/spebase/run.c
@@ -102,7 +102,7 @@ int _base_spe_context_run(spe_context_pt
 		spe_stop_info_t *stopinfo)
 {
 	int retval = 0, run_rc;
-	unsigned int run_status;
+	unsigned int run_status, tmp_entry;
 	spe_stop_info_t	stopinfo_buf;
 	struct spe_context_info this_context_info __attribute__((cleanup(cleanupspeinfo)));
 
@@ -111,13 +111,20 @@ int _base_spe_context_run(spe_context_pt
 	if (!stopinfo)
 		stopinfo = &stopinfo_buf;
 
-	if (*entry == SPE_DEFAULT_ENTRY)
-		*entry = spe->base_private->entry;
+
+	/* In emulated isolated mode, the npc will always return as zero.
+	 * use our private entry point instead */
+	if (spe->base_private->flags & SPE_ISOLATE_EMULATE)
+		tmp_entry = spe->base_private->emulated_entry;
+
+	else if (*entry == SPE_DEFAULT_ENTRY)
+		tmp_entry = spe->base_private->entry;
 
 	/* If we're starting the SPE binary from its original entry point,
 	 * setup the arguments to main() */
-	if (*entry == spe->base_private->entry &&
-			!(spe->base_private->flags & SPE_ISOLATE)) {
+	if (tmp_entry == spe->base_private->entry &&
+			!(spe->base_private->flags &
+				(SPE_ISOLATE | SPE_ISOLATE_EMULATE))) {
 
 		addr64 argp64, envp64, tid64, ls64;
 		unsigned int regs[128][4];
@@ -179,23 +186,32 @@ int _base_spe_context_run(spe_context_pt
 
 do_run:
 	/*Remember the npc value*/
-	__spe_current_active_context->npc = *entry;
+	__spe_current_active_context->npc = tmp_entry;
 
 	/* run SPE context */
-	run_rc = spu_run(spe->base_private->fd_spe_dir, entry, &run_status);
+	run_rc = spu_run(spe->base_private->fd_spe_dir,
+			&tmp_entry, &run_status);
 
 	/*Remember the npc value*/
-	__spe_current_active_context->npc = *entry;
+	__spe_current_active_context->npc = tmp_entry;
 	__spe_current_active_context->status = run_status;
 
 	DEBUG_PRINTF("spu_run returned run_rc=0x%08x, entry=0x%04x, "
-			"ext_status=0x%04x.\n", run_rc, *entry, run_status);
+			"ext_status=0x%04x.\n", run_rc, tmp_entry, run_status);
 
 	/* set up return values and stopinfo according to spu_run exit
 	 * conditions. This is overwritten on error.
 	 */
 	stopinfo->spu_status = run_rc;
 
+	if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
+		/* save the entry point, and pretend that the npc is zero */
+		spe->base_private->emulated_entry = tmp_entry;
+		*entry = 0;
+	} else {
+		*entry = tmp_entry;
+	}
+
 	/* Return with stopinfo set on syscall error paths */
 	if (run_rc == -1) {
 		DEBUG_PRINTF("spu_run returned error %d, errno=%d\n",
@@ -265,7 +281,7 @@ do_run:
 			} else {
 				/* successful library callback - restart the SPE
 				 * program at the next instruction */
-				*entry += 4;
+				tmp_entry += 4;
 				goto do_run;
 			}
 
Index: libspe2/spebase/lib_builtin.c
===================================================================
--- libspe2.orig/spebase/lib_builtin.c
+++ libspe2/spebase/lib_builtin.c
@@ -150,6 +150,12 @@ int handle_library_callback(struct spe_c
 
 	handler=handlers[callnum];
 	
+	/* For emulated isolation mode, position the
+	 * npc so that the buffer for the PPE-assisted
+	 * library calls can be accessed. */
+	if (spe->base_private->flags & SPE_ISOLATE_EMULATE)
+		npc = SPE_EMULATE_PARAM_BUFFER;
+
 	rc = handler(spe->base_private->mem_mmap_base, npc);
 	if (rc) {
 		DEBUG_PRINTF ("SPE library call unsupported.\n");



More information about the cbe-oss-dev mailing list